diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml
index 0dcafa7a44..bb90188c4c 100644
--- a/.github/workflows/lock.yml
+++ b/.github/workflows/lock.yml
@@ -14,7 +14,7 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- - uses: dessant/lock-threads@v3
+ - uses: dessant/lock-threads@v4
with:
github-token: ${{ github.token }}
issue-inactive-days: 14
diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py
index c5585fd463..fbb34bc7e6 100755
--- a/frappe/core/doctype/communication/email.py
+++ b/frappe/core/doctype/communication/email.py
@@ -92,7 +92,7 @@ def make(
send_me_a_copy=cint(send_me_a_copy),
cc=cc,
bcc=bcc,
- read_receipt=read_receipt,
+ read_receipt=cint(read_receipt),
print_letterhead=print_letterhead,
email_template=email_template,
communication_type=communication_type,
diff --git a/frappe/core/doctype/rq_job/test_rq_job.py b/frappe/core/doctype/rq_job/test_rq_job.py
index 654cdcd21f..2fbefda056 100644
--- a/frappe/core/doctype/rq_job/test_rq_job.py
+++ b/frappe/core/doctype/rq_job/test_rq_job.py
@@ -38,7 +38,6 @@ class TestRQJob(FrappeTestCase):
"name": job.id,
"queue": "short",
"job_name": self.BG_JOB,
- "status": "queued",
"exc_info": None,
},
rq_job,
diff --git a/frappe/core/doctype/system_settings/system_settings.json b/frappe/core/doctype/system_settings/system_settings.json
index 57e2b1a1be..f9d7adceef 100644
--- a/frappe/core/doctype/system_settings/system_settings.json
+++ b/frappe/core/doctype/system_settings/system_settings.json
@@ -33,7 +33,6 @@
"allow_guests_to_upload_files",
"security",
"session_expiry",
- "session_expiry_mobile",
"document_share_key_expiry",
"column_break_13",
"deny_multiple_sessions",
@@ -211,13 +210,6 @@
"fieldtype": "Data",
"label": "Session Expiry (idle timeout)"
},
- {
- "default": "720:00",
- "description": "In Hours",
- "fieldname": "session_expiry_mobile",
- "fieldtype": "Data",
- "label": "Session Expiry Mobile"
- },
{
"fieldname": "column_break_13",
"fieldtype": "Column Break"
@@ -517,7 +509,7 @@
"icon": "fa fa-cog",
"issingle": 1,
"links": [],
- "modified": "2022-11-20 17:57:05.099512",
+ "modified": "2022-11-28 17:57:05.099512",
"modified_by": "Administrator",
"module": "Core",
"name": "System Settings",
diff --git a/frappe/core/doctype/system_settings/system_settings.py b/frappe/core/doctype/system_settings/system_settings.py
index 1fc27ca114..0f7a7f0819 100644
--- a/frappe/core/doctype/system_settings/system_settings.py
+++ b/frappe/core/doctype/system_settings/system_settings.py
@@ -20,11 +20,10 @@ class SystemSettings(Document):
elif not enable_password_policy:
self.minimum_password_score = ""
- for key in ("session_expiry", "session_expiry_mobile"):
- if self.get(key):
- parts = self.get(key).split(":")
- if len(parts) != 2 or not (cint(parts[0]) or cint(parts[1])):
- frappe.throw(_("Session Expiry must be in format {0}").format("hh:mm"))
+ if self.session_expiry:
+ parts = self.session_expiry.split(":")
+ if len(parts) != 2 or not (cint(parts[0]) or cint(parts[1])):
+ frappe.throw(_("Session Expiry must be in format {0}").format("hh:mm"))
if self.enable_two_factor_auth:
if self.two_factor_method == "SMS":
diff --git a/frappe/database/mariadb/framework_mariadb.sql b/frappe/database/mariadb/framework_mariadb.sql
index 70b37dfcf8..efeeaaf935 100644
--- a/frappe/database/mariadb/framework_mariadb.sql
+++ b/frappe/database/mariadb/framework_mariadb.sql
@@ -252,7 +252,6 @@ CREATE TABLE `tabSessions` (
`sessiondata` longtext,
`ipaddress` varchar(16) DEFAULT NULL,
`lastupdate` datetime(6) DEFAULT NULL,
- `device` varchar(255) DEFAULT 'desktop',
`status` varchar(20) DEFAULT NULL,
KEY `sid` (`sid`)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC CHARACTER SET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
diff --git a/frappe/database/mariadb/setup_db.py b/frappe/database/mariadb/setup_db.py
index 6c68a7692c..67f809abf7 100644
--- a/frappe/database/mariadb/setup_db.py
+++ b/frappe/database/mariadb/setup_db.py
@@ -1,17 +1,11 @@
import os
+import click
+
import frappe
from frappe.database.db_manager import DbManager
-expected_settings_10_2_earlier = {
- "innodb_file_format": "Barracuda",
- "innodb_file_per_table": "ON",
- "innodb_large_prefix": "ON",
- "character_set_server": "utf8mb4",
- "collation_server": "utf8mb4_unicode_ci",
-}
-
-expected_settings_10_3_later = {
+REQUIRED_MARIADB_CONFIG = {
"character_set_server": "utf8mb4",
"collation_server": "utf8mb4_unicode_ci",
}
@@ -109,16 +103,13 @@ def import_db_from_sql(source_sql=None, verbose=False):
def check_database_settings():
- mariadb_variables = get_mariadb_variables()
- versions = get_mariadb_version(mariadb_variables.get("version"))
- if versions[0] <= "10.2":
- expected_variables = expected_settings_10_2_earlier
- else:
- expected_variables = expected_settings_10_3_later
+
+ check_compatible_versions()
# Check each expected value vs. actuals:
+ mariadb_variables = get_mariadb_variables()
result = True
- for key, expected_value in expected_variables.items():
+ for key, expected_value in REQUIRED_MARIADB_CONFIG.items():
if mariadb_variables.get(key) != expected_value:
print(
"For key %s. Expected value %s, found value %s"
@@ -130,8 +121,7 @@ def check_database_settings():
print(
(
"{sep2}Creation of your site - {site} failed because MariaDB is not properly {sep}"
- "configured. If using version 10.2.x or earlier, make sure you use the {sep}"
- "the Barracuda storage engine.{sep2}"
+ "configured.{sep2}"
"Please verify the above settings in MariaDB's my.cnf. Restart MariaDB.{sep}"
"And then run `bench new-site {site}` again.{sep2}"
).format(site=frappe.local.site, sep2="\n\n", sep="\n")
@@ -140,6 +130,28 @@ def check_database_settings():
return result
+def check_compatible_versions():
+ try:
+ version = get_mariadb_version()
+ version_tuple = tuple(int(v) for v in version[0].split("."))
+
+ if version_tuple < (10, 6):
+ click.secho(
+ f"Warning: MariaDB version {version} is less than 10.6 which is not supported by Frappe",
+ fg="yellow",
+ )
+ elif version_tuple >= (10, 9):
+ click.secho(
+ f"Warning: MariaDB version {version} is more than 10.8 which is not yet tested with Frappe Framework.",
+ fg="yellow",
+ )
+ except Exception:
+ click.secho(
+ "MariaDB version compatibility checks failed, make sure you're running a supported version.",
+ fg="yellow",
+ )
+
+
def get_root_connection(root_login, root_password):
import getpass
diff --git a/frappe/database/postgres/framework_postgres.sql b/frappe/database/postgres/framework_postgres.sql
index 7ce3cecff8..37605be0f6 100644
--- a/frappe/database/postgres/framework_postgres.sql
+++ b/frappe/database/postgres/framework_postgres.sql
@@ -256,7 +256,6 @@ CREATE TABLE "tabSessions" (
"sessiondata" text,
"ipaddress" varchar(16) DEFAULT NULL,
"lastupdate" timestamp(6) DEFAULT NULL,
- "device" varchar(255) DEFAULT 'desktop',
"status" varchar(20) DEFAULT NULL
);
diff --git a/frappe/defaults.py b/frappe/defaults.py
index 744a3fad5d..fcfef0b2fc 100644
--- a/frappe/defaults.py
+++ b/frappe/defaults.py
@@ -241,4 +241,6 @@ def get_defaults_for(parent="__default"):
def _clear_cache(parent):
+ if frappe.flags.in_install:
+ return
frappe.clear_cache(user=parent if parent not in common_default_keys else None)
diff --git a/frappe/desk/form/meta.py b/frappe/desk/form/meta.py
index ee975c8326..b5b58ebfa3 100644
--- a/frappe/desk/form/meta.py
+++ b/frappe/desk/form/meta.py
@@ -156,6 +156,9 @@ class FormMeta(Meta):
list_script = ""
form_script = ""
for script in client_scripts:
+ if not script.script:
+ continue
+
if script.view == "List":
list_script += f"""
// {script.name}
@@ -163,7 +166,7 @@ class FormMeta(Meta):
"""
- if script.view == "Form":
+ elif script.view == "Form":
form_script += f"""
// {script.name}
{script.script}
diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py
index a1e8a9368f..b4a51ffaf3 100644
--- a/frappe/desk/query_report.py
+++ b/frappe/desk/query_report.py
@@ -319,7 +319,7 @@ def format_duration_fields(data: frappe._dict) -> None:
continue
for row in data.result:
- index = col.fieldname if isinstance(row, dict) else i
+ index = col.get("fieldname") if isinstance(row, dict) else i
if row[index]:
row[index] = format_duration(row[index])
diff --git a/frappe/email/receive.py b/frappe/email/receive.py
index 0cf01083f7..7028dc1f11 100644
--- a/frappe/email/receive.py
+++ b/frappe/email/receive.py
@@ -987,10 +987,10 @@ class TimerMixin:
self.sock.settimeout(self.timeout / 5.0)
def _getline(self, *args, **kwargs):
- start_time = time.time()
+ start_time = time.monotonic()
ret = self._super._getline(self, *args, **kwargs)
- self.elapsed_time += time.time() - start_time
+ self.elapsed_time += time.monotonic() - start_time
if self.timeout and self.elapsed_time > self.timeout:
raise EmailTimeoutError
diff --git a/frappe/geo/doctype/country/country.py b/frappe/geo/doctype/country/country.py
index f6be7a078d..8b1ec1364f 100644
--- a/frappe/geo/doctype/country/country.py
+++ b/frappe/geo/doctype/country/country.py
@@ -1,8 +1,63 @@
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
-from frappe.model.document import Document
+import frappe
+from frappe.model.document import Document, bulk_insert
class Country(Document):
+ # NOTE: During installation country docs are bulk inserted.
pass
+
+
+def import_country_and_currency():
+ from frappe.geo.doctype.currency.currency import enable_default_currencies
+
+ countries, currencies = get_countries_and_currencies()
+
+ bulk_insert("Country", countries, ignore_duplicates=True)
+ bulk_insert("Currency", currencies, ignore_duplicates=True)
+
+ enable_default_currencies()
+
+
+def get_countries_and_currencies():
+ from frappe.geo.country_info import get_all as get_geo_data
+
+ data = get_geo_data()
+
+ countries = []
+ currencies = []
+
+ added_currencies = set()
+
+ for name, country in data.items():
+ country = frappe._dict(country)
+ countries.append(
+ frappe.get_doc(
+ doctype="Country",
+ name=name,
+ country_name=name,
+ code=country.code,
+ date_format=country.date_format or "dd-mm-yyyy",
+ time_format=country.time_format or "HH:mm:ss",
+ time_zones="\n".join(country.timezones or []),
+ )
+ )
+ if country.currency and country.currency not in added_currencies:
+ added_currencies.add(country.currency)
+
+ currencies.append(
+ frappe.get_doc(
+ doctype="Currency",
+ name=country.currency,
+ currency_name=country.currency,
+ fraction=country.currency_fraction,
+ symbol=country.currency_symbol,
+ fraction_units=country.currency_fraction_units,
+ smallest_currency_fraction_value=country.smallest_currency_fraction_value,
+ number_format=country.number_format,
+ )
+ )
+
+ return countries, currencies
diff --git a/frappe/geo/doctype/country/test_country.py b/frappe/geo/doctype/country/test_country.py
index ecc2fb6863..cf4590aabc 100644
--- a/frappe/geo/doctype/country/test_country.py
+++ b/frappe/geo/doctype/country/test_country.py
@@ -2,5 +2,52 @@
# License: MIT. See LICENSE
import frappe
+from frappe.geo.doctype.country.country import (
+ get_countries_and_currencies,
+ import_country_and_currency,
+)
+from frappe.geo.doctype.currency.currency import enable_default_currencies
+from frappe.tests.utils import FrappeTestCase
test_records = frappe.get_test_records("Country")
+
+
+def get_table_snapshot(doctype):
+ data = frappe.db.sql(f"select * from `tab{doctype}` order by name", as_dict=True)
+
+ inconsequential_keys = ["modified", "creation"]
+ for row in data:
+ for key in inconsequential_keys:
+ row.pop(key, None)
+ return data
+
+
+class TestCountry(FrappeTestCase):
+ def test_bulk_insert_correctness(self):
+ def clear_tables():
+ frappe.db.delete("Currency")
+ frappe.db.delete("Country")
+
+ # Clear data
+ clear_tables()
+
+ # Reimport and verify same results
+ import_country_and_currency()
+
+ countries_before = get_table_snapshot("Country")
+ currencies_before = get_table_snapshot("Currency")
+
+ clear_tables()
+
+ countries, currencies = get_countries_and_currencies()
+ for country in countries:
+ country.db_insert(ignore_if_duplicate=True)
+ for currency in currencies:
+ currency.db_insert(ignore_if_duplicate=True)
+ enable_default_currencies()
+
+ countries_after = get_table_snapshot("Country")
+ currencies_after = get_table_snapshot("Currency")
+
+ self.assertEqual(countries_before, countries_after)
+ self.assertEqual(currencies_before, currencies_after)
diff --git a/frappe/geo/doctype/currency/currency.py b/frappe/geo/doctype/currency/currency.py
index 93bcc063f8..51317e8771 100644
--- a/frappe/geo/doctype/currency/currency.py
+++ b/frappe/geo/doctype/currency/currency.py
@@ -4,8 +4,14 @@
import frappe
from frappe.model.document import Document
+DEFAULT_ENABLED_CURRENCIES = ("INR", "USD", "GBP", "EUR", "AED", "AUD", "JPY", "CNY", "CHF")
+
class Currency(Document):
+ # NOTE: During installation country docs are bulk inserted.
def validate(self):
- if not frappe.flags.in_install_app:
- frappe.clear_cache()
+ frappe.clear_cache()
+
+
+def enable_default_currencies():
+ frappe.db.set_value("Currency", {"name": ("in", DEFAULT_ENABLED_CURRENCIES)}, "enabled", 1)
diff --git a/frappe/installer.py b/frappe/installer.py
index 0cd9b32063..e78112df19 100644
--- a/frappe/installer.py
+++ b/frappe/installer.py
@@ -16,6 +16,7 @@ import frappe
from frappe.defaults import _clear_cache
from frappe.utils import cint, is_git_url
from frappe.utils.dashboard import sync_dashboards
+from frappe.utils.synchronization import filelock
def _is_scheduler_enabled() -> bool:
@@ -540,8 +541,11 @@ def make_site_config(
f.write(json.dumps(site_config, indent=1, sort_keys=True))
+@filelock("site_config")
def update_site_config(key, value, validate=True, site_config_path=None):
"""Update a value in site_config"""
+ from frappe.utils.synchronization import filelock
+
if not site_config_path:
site_config_path = get_site_config_path()
diff --git a/frappe/integrations/doctype/google_drive/google_drive.json b/frappe/integrations/doctype/google_drive/google_drive.json
index 6742d9ee5d..592281be68 100644
--- a/frappe/integrations/doctype/google_drive/google_drive.json
+++ b/frappe/integrations/doctype/google_drive/google_drive.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2019-08-13 17:24:05.470876",
"doctype": "DocType",
"engine": "InnoDB",
@@ -100,7 +101,8 @@
}
],
"issingle": 1,
- "modified": "2020-09-18 17:26:09.703215",
+ "links": [],
+ "modified": "2022-12-04 15:53:58.702389",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Google Drive",
@@ -115,19 +117,10 @@
"role": "System Manager",
"share": 1,
"write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "role": "All",
- "share": 1,
- "write": 1
}
],
"sort_field": "modified",
"sort_order": "ASC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
diff --git a/frappe/integrations/doctype/ldap_settings/ldap_settings.json b/frappe/integrations/doctype/ldap_settings/ldap_settings.json
index f5472a5097..b8f73cebed 100644
--- a/frappe/integrations/doctype/ldap_settings/ldap_settings.json
+++ b/frappe/integrations/doctype/ldap_settings/ldap_settings.json
@@ -24,6 +24,7 @@
"ldap_email_field",
"ldap_username_field",
"ldap_first_name_field",
+ "do_not_create_new_user",
"column_break_19",
"ldap_middle_name_field",
"ldap_last_name_field",
@@ -289,12 +290,19 @@
"fieldname": "section_break_40",
"fieldtype": "Section Break",
"hide_border": 1
+ },
+ {
+ "default": "0",
+ "description": "Do not create new user if user with email does not exist in the system",
+ "fieldname": "do_not_create_new_user",
+ "fieldtype": "Check",
+ "label": "Do Not Create New User "
}
],
"in_create": 1,
"issingle": 1,
"links": [],
- "modified": "2022-07-07 16:51:46.230793",
+ "modified": "2022-12-05 21:52:31.146035",
"modified_by": "Administrator",
"module": "Integrations",
"name": "LDAP Settings",
diff --git a/frappe/integrations/doctype/ldap_settings/ldap_settings.py b/frappe/integrations/doctype/ldap_settings/ldap_settings.py
index 48e1f12bdb..094c440672 100644
--- a/frappe/integrations/doctype/ldap_settings/ldap_settings.py
+++ b/frappe/integrations/doctype/ldap_settings/ldap_settings.py
@@ -172,7 +172,7 @@ class LDAPSettings(Document):
if frappe.db.exists("User", user_data["email"]):
user = frappe.get_doc("User", user_data["email"])
LDAPSettings.update_user_fields(user=user, user_data=user_data)
- else:
+ elif not self.do_not_create_new_user:
doc = user_data | {
"doctype": "User",
"send_welcome_email": 0,
@@ -181,6 +181,12 @@ class LDAPSettings(Document):
}
user = frappe.get_doc(doc)
user.insert(ignore_permissions=True)
+ else:
+ frappe.throw(
+ _(
+ "User with email: {0} does not exist in the system. Please ask 'System Administrator' to create the user for you."
+ ).format(user_data["email"])
+ )
if self.default_user_type == "System User":
role = self.default_role
@@ -324,11 +330,21 @@ class LDAPSettings(Document):
def convert_ldap_entry_to_dict(self, user_entry: Entry):
# support multiple email values
- email = user_entry[self.ldap_email_field]
+ email = user_entry[self.ldap_email_field].value
+
+ if isinstance(email, list):
+ # check if any of the email in the list already exist
+ for e in email:
+ if frappe.db.exists("User", e):
+ email = e
+ break
+ else:
+ # if none of the email exist, use the first email
+ email = email[0]
data = {
"username": user_entry[self.ldap_username_field].value,
- "email": str(email.value[0] if isinstance(email.value, list) else email.value),
+ "email": email,
"first_name": user_entry[self.ldap_first_name_field].value,
}
diff --git a/frappe/model/document.py b/frappe/model/document.py
index c1d4575ae7..e6f90b2260 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -708,17 +708,16 @@ class Document(BaseDocument):
d.reset_values_if_no_permlevel_access(has_access_to, high_permlevel_fields)
def get_permlevel_access(self, permission_type="write"):
- if not hasattr(self, "_has_access_to"):
- self._has_access_to = {}
-
- self._has_access_to[permission_type] = []
+ allowed_permlevels = []
roles = frappe.get_roles()
- for perm in self.get_permissions():
- if perm.role in roles and perm.get(permission_type):
- if perm.permlevel not in self._has_access_to[permission_type]:
- self._has_access_to[permission_type].append(perm.permlevel)
- return self._has_access_to[permission_type]
+ for perm in self.get_permissions():
+ if (
+ perm.role in roles and perm.get(permission_type) and perm.permlevel not in allowed_permlevels
+ ):
+ allowed_permlevels.append(perm.permlevel)
+
+ return allowed_permlevels
def has_permlevel_access_to(self, fieldname, df=None, permission_type="read"):
if not df:
@@ -1506,16 +1505,18 @@ class Document(BaseDocument):
if self in frappe.local.locked_documents:
frappe.local.locked_documents.remove(self)
- # validation helpers
- def validate_from_to_dates(self, from_date_field, to_date_field):
- """
- Generic validation to verify date sequence
- """
- if date_diff(self.get(to_date_field), self.get(from_date_field)) < 0:
+ def validate_from_to_dates(self, from_date_field: str, to_date_field: str) -> None:
+ """Validate that the value of `from_date_field` is not later than the value of `to_date_field`."""
+ from_date = self.get(from_date_field)
+ to_date = self.get(to_date_field)
+ if not (from_date and to_date):
+ return
+
+ if date_diff(to_date, from_date) < 0:
frappe.throw(
_("{0} must be after {1}").format(
- frappe.bold(self.meta.get_label(to_date_field)),
- frappe.bold(self.meta.get_label(from_date_field)),
+ frappe.bold(_(self.meta.get_label(to_date_field))),
+ frappe.bold(_(self.meta.get_label(from_date_field))),
),
frappe.exceptions.InvalidDates,
)
diff --git a/frappe/model/meta.py b/frappe/model/meta.py
index ce30011d02..d9d18e98ce 100644
--- a/frappe/model/meta.py
+++ b/frappe/model/meta.py
@@ -259,14 +259,13 @@ class Meta(Document):
def get_label(self, fieldname):
"""Get label of the given fieldname"""
-
if df := self.get_field(fieldname):
return df.label
if fieldname in DEFAULT_FIELD_LABELS:
return DEFAULT_FIELD_LABELS[fieldname]()
- return _("No Label")
+ return "No Label"
def get_options(self, fieldname):
return self.get_field(fieldname).options
diff --git a/frappe/modules/patch_handler.py b/frappe/modules/patch_handler.py
index 00d0e8167d..15144a1630 100644
--- a/frappe/modules/patch_handler.py
+++ b/frappe/modules/patch_handler.py
@@ -173,7 +173,7 @@ def execute_patch(patchmodule, method=None, methodargs=None):
f"Executing {patchmodule or methodargs} in {frappe.local.site} ({frappe.db.cur_db_name}){docstring}"
)
- start_time = time.time()
+ start_time = time.monotonic()
frappe.db.begin()
frappe.db.auto_commit_on_many_writes = 0
try:
@@ -197,7 +197,7 @@ def execute_patch(patchmodule, method=None, methodargs=None):
else:
frappe.db.commit()
- end_time = time.time()
+ end_time = time.monotonic()
_patch_mode(False)
print(f"Success: Done in {round(end_time - start_time, 3)}s")
diff --git a/frappe/parallel_test_runner.py b/frappe/parallel_test_runner.py
index 905296c5f3..b7c3966df1 100644
--- a/frappe/parallel_test_runner.py
+++ b/frappe/parallel_test_runner.py
@@ -42,7 +42,7 @@ class ParallelTestRunner:
self.before_test_setup()
def before_test_setup(self):
- start_time = time.time()
+ start_time = time.monotonic()
for fn in frappe.get_hooks("before_tests", app_name=self.app):
frappe.get_attr(fn)()
@@ -52,7 +52,7 @@ class ParallelTestRunner:
for doctype in test_module.global_test_dependencies:
make_test_records(doctype, commit=True)
- elapsed = time.time() - start_time
+ elapsed = time.monotonic() - start_time
elapsed = click.style(f" ({elapsed:.03}s)", fg="red")
click.echo(f"Before Test {elapsed}")
@@ -162,7 +162,7 @@ def split_by_weight(work, weights, chunk_count):
class ParallelTestResult(unittest.TextTestResult):
def startTest(self, test):
self.tb_locals = True
- self._started_at = time.time()
+ self._started_at = time.monotonic()
super(unittest.TextTestResult, self).startTest(test)
test_class = unittest.util.strclass(test.__class__)
if not hasattr(self, "current_test_class") or self.current_test_class != test_class:
@@ -174,7 +174,7 @@ class ParallelTestResult(unittest.TextTestResult):
def addSuccess(self, test):
super(unittest.TextTestResult, self).addSuccess(test)
- elapsed = time.time() - self._started_at
+ elapsed = time.monotonic() - self._started_at
threshold_passed = elapsed >= SLOW_TEST_THRESHOLD
elapsed = click.style(f" ({elapsed:.03}s)", fg="red") if threshold_passed else ""
click.echo(f" {click.style(' ✔ ', fg='green')} {self.getTestMethodName(test)}{elapsed}")
diff --git a/frappe/permissions.py b/frappe/permissions.py
index 0307952c62..2997165dc9 100644
--- a/frappe/permissions.py
+++ b/frappe/permissions.py
@@ -427,7 +427,9 @@ def get_roles(user=None, with_standard=True):
table = DocType("Has Role")
roles = (
frappe.qb.from_(table)
- .where((table.parent == user) & (table.role.notin(["All", "Guest"])))
+ .where(
+ (table.parenttype == "User") & (table.parent == user) & (table.role.notin(["All", "Guest"]))
+ )
.select(table.role)
.run(pluck=True)
)
diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js
index a4647af480..e070e1db0b 100644
--- a/frappe/public/js/frappe/form/layout.js
+++ b/frappe/public/js/frappe/form/layout.js
@@ -482,10 +482,37 @@ frappe.ui.form.Layout = class Layout {
}
setup_events() {
+ let last_scroll = 0;
+ let tabs_list = $(".form-tabs-list");
+ let tabs_content = this.tabs_content[0];
+ if (!tabs_list.length) return;
+
+ $(window).scroll(
+ frappe.utils.throttle(() => {
+ let current_scroll = document.documentElement.scrollTop;
+ if (current_scroll > 0 && last_scroll <= current_scroll) {
+ tabs_list.removeClass("form-tabs-sticky-down");
+ tabs_list.addClass("form-tabs-sticky-up");
+ } else {
+ tabs_list.removeClass("form-tabs-sticky-up");
+ tabs_list.addClass("form-tabs-sticky-down");
+ }
+ last_scroll = current_scroll;
+ }, 500)
+ );
+
this.tab_link_container.off("click").on("click", ".nav-link", (e) => {
e.preventDefault();
e.stopImmediatePropagation();
$(e.currentTarget).tab("show");
+ if (tabs_content.getBoundingClientRect().top < 100) {
+ tabs_content.scrollIntoView();
+ setTimeout(() => {
+ $(".page-head").css("top", "-15px");
+ $(".form-tabs-list").removeClass("form-tabs-sticky-down");
+ $(".form-tabs-list").addClass("form-tabs-sticky-up");
+ }, 3);
+ }
});
}
diff --git a/frappe/public/js/frappe/model/model.js b/frappe/public/js/frappe/model/model.js
index 4aa90a0efb..18acf00ad3 100644
--- a/frappe/public/js/frappe/model/model.js
+++ b/frappe/public/js/frappe/model/model.js
@@ -699,6 +699,8 @@ $.extend(frappe.model, {
doctype: doctype,
name: docname,
},
+ freeze: true,
+ freeze_message: __("Deleting {0}...", [title]),
callback: function (r, rt) {
if (!r.exc) {
frappe.utils.play_sound("delete");
diff --git a/frappe/public/js/frappe/ui/page.js b/frappe/public/js/frappe/ui/page.js
index 2cb4f41038..b0df2d60fe 100644
--- a/frappe/public/js/frappe/ui/page.js
+++ b/frappe/public/js/frappe/ui/page.js
@@ -47,8 +47,7 @@ frappe.ui.Page = class Page {
setup_scroll_handler() {
let last_scroll = 0;
- window.addEventListener(
- "scroll",
+ $(window).scroll(
frappe.utils.throttle(() => {
$(".page-head").toggleClass("drop-shadow", !!document.documentElement.scrollTop);
let current_scroll = document.documentElement.scrollTop;
@@ -58,8 +57,7 @@ frappe.ui.Page = class Page {
$(".page-head").css("top", "var(--navbar-height)");
}
last_scroll = current_scroll;
- }),
- 500
+ }, 500)
);
}
diff --git a/frappe/public/js/frappe/ui/toolbar/fuzzy_match.js b/frappe/public/js/frappe/ui/toolbar/fuzzy_match.js
index 765377a0b4..9f86b03744 100644
--- a/frappe/public/js/frappe/ui/toolbar/fuzzy_match.js
+++ b/frappe/public/js/frappe/ui/toolbar/fuzzy_match.js
@@ -14,7 +14,7 @@
// J�rgen Tjern� - async helper
// Anurag Awasthi - updated to 0.2.0
-const SEQUENTIAL_BONUS = 15; // bonus for adjacent matches
+const SEQUENTIAL_BONUS = 25; // bonus for adjacent matches
const SEPARATOR_BONUS = 30; // bonus if match occurs after a separator
const CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower
const FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched
diff --git a/frappe/public/js/frappe/web_form/web_form.js b/frappe/public/js/frappe/web_form/web_form.js
index 52d417f025..980df7129b 100644
--- a/frappe/public/js/frappe/web_form/web_form.js
+++ b/frappe/public/js/frappe/web_form/web_form.js
@@ -379,7 +379,6 @@ export default class WebForm extends frappe.ui.FieldGroup {
args: {
data: this.doc,
web_form: this.name,
- docname: this.doc.name,
for_payment,
},
callback: (response) => {
diff --git a/frappe/public/scss/desk/form.scss b/frappe/public/scss/desk/form.scss
index 655c0a1539..183c4b9033 100644
--- a/frappe/public/scss/desk/form.scss
+++ b/frappe/public/scss/desk/form.scss
@@ -319,8 +319,13 @@
}
.form-tabs-list {
+ position: sticky;
+ background-color: var(--card-bg);
+ z-index: 5;
+ transition: 0.5s top;
padding-left: var(--padding-xs);
- border-bottom: 1px solid var(--border-color);
+ border-bottom: 2px solid var(--border-color);
+ border-radius: var(--border-radius-md) var(--border-radius-md) 0 0;
.form-tabs {
.nav-item {
@@ -338,6 +343,15 @@
}
}
}
+.form-tab-content {
+ scroll-margin-top: calc(var(--navbar-height) + 52px);
+}
+.form-tabs-sticky-up {
+ top: calc(var(--navbar-height) - 1px);
+}
+.form-tabs-sticky-down {
+ top: calc(var(--navbar-height) + var(--page-head-height) - 1px);
+}
.progress-area {
padding-top: var(--padding-md);
diff --git a/frappe/query_builder/docs.md b/frappe/query_builder/docs.md
new file mode 100644
index 0000000000..c1f170b3d4
--- /dev/null
+++ b/frappe/query_builder/docs.md
@@ -0,0 +1,117 @@
+# This documentation is added for query builder and related files.
+
+## Related Files
+
+- [builder](./builder.py)
+- [custom](./custom.py)
+- [functions](./functions.py)
+- [terms](./terms.py)
+- [query](../database/query.py)
+
+### Builder
+
+Database specefic classes are declared which are then selected during init to give either postgres or mariadb dialects.
+
+### Functions and Custom
+
+These file handle any custom function which needs to be either added or handled sperately by the different dialects which are not supported yet by pypika directly.
+
+### Terms
+
+The inherent terms or specefic classes of pypika builder are handled and declared here all the parameterization goes through this module (custom parameterization is also implemeted here).
+
+### Raw Query Generation Examples
+
+Check out some examples [here](https://frappeframework.com/docs/v14/user/en/api/query-builder)
+
+
Query
+
+## Goal
+
+```sql
+select `name` from `tabUser`
+```
+
+## There are 3 major ways to reach this goal
+
+### 1. Direct SQL (Boring / Unsafe / inconsistent)
+
+```python
+frappe.db.sql("select `name` from `tabUser`")
+```
+
+### 2. SQL through direct Query Builder objects
+
+```python
+from frappe.query_builder import Field
+
+frappe.qb.from_("User").select(Field("name"))
+
+```
+
+### 3. Through the database API (Which performs the second method under the hood)
+
+```python
+frappe.db.get_values("User", fieldname="name", filters={})
+```
+
+This module is used to support the 3rd way of query generation in frappe.
+The database module is completely powered by this query module.
+This module is also where the query `Engine` resides which is the class responsible for the handling of various filter & field notations.
+
+- Interating with the existing Database API.
+ - The old database API was running on raw sql generation in order to bridge the gap between the added new support and raw sql strings this intermediate module was added.
+
+This module supports almost all the features present in db_query which powers `frappe.get_all` and `frappe.get_list`
+
+Supporting all the features with the previous filter notations and the field notations few features were added -:
+
+1. Dict Query
+
+ - To support this
+
+ ```python
+ frappe.db.get_values("ToDo", fieldname="name", filters={"description": "Something Random"})
+ ```
+
+ and many other possible caveats to the dict representation such as
+
+ ```python
+ frappe.db.get_values("User", fieldname="name",
+ filters={"name": ("like", "admin%")})
+
+ frappe.db.get_values("ToDo", fieldname="name", filters={"description": ("in", ["somso%", "someome"])})
+ ```
+
+2. Misc Query
+
+ - To support this
+
+ ```python
+ frappe.db.get_values("ToDo", fieldname="name", filters=["description", "=", "someone"])
+ ```
+
+ Along with other possible list filter use cases including implicit joins
+
+3. Criterion Query
+
+ - To support Inherent Query Builder objects
+
+ ```python
+ from frappe.query_builder import Field
+
+ frappe.db.get_values("User", fieldname="name", filters=Field("name") == "Administrator")
+
+ ```
+
+ and all the pypika filters and functions.
+
+## Things to be implemented in the `Engine`
+
+### 1. Support for Permissions
+
+As of now query builder has no concept of permissions and moving towards a singular database API this needs to be added in the `Engine`.
+
+### 2. Implementing the missing features which are present in `frappe.get_list` and `frappe.get_all` (do we even need so much magic?)
+
+Moving to a singular Database API (database.py + db_query.py) all the support present in `get_list` and `get_all` needs to be present in the new `Engine` as well however this creates alot of security cracks, so moving the a *new and more restrictive version* of the database API with backward compatibility perhaps would be the right way to go?
diff --git a/frappe/recorder.py b/frappe/recorder.py
index 6df3077fa5..b00f15c6b5 100644
--- a/frappe/recorder.py
+++ b/frappe/recorder.py
@@ -20,9 +20,9 @@ TRACEBACK_PATH_PATTERN = re.compile(".*/apps/")
def sql(*args, **kwargs):
- start_time = time.time()
+ start_time = time.monotonic()
result = frappe.db._sql(*args, **kwargs)
- end_time = time.time()
+ end_time = time.monotonic()
stack = list(get_current_stack_frames())
query = sqlparse.format(str(frappe.db.last_query).strip(), keyword_case="upper", reindent=True)
diff --git a/frappe/sessions.py b/frappe/sessions.py
index 20891db2e6..9c739f3a96 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -32,12 +32,11 @@ def clear():
frappe.response["message"] = _("Cache Cleared")
-def clear_sessions(user=None, keep_current=False, device=None, force=False):
+def clear_sessions(user=None, keep_current=False, force=False):
"""Clear other sessions of the current user. Called at login / logout
:param user: user name (default: current user)
:param keep_current: keep current session (default: false)
- :param device: delete sessions of this device (default: desktop, mobile)
:param force: triggered by the user (default false)
"""
@@ -45,35 +44,26 @@ def clear_sessions(user=None, keep_current=False, device=None, force=False):
if force:
reason = "Force Logged out by the user"
- for sid in get_sessions_to_clear(user, keep_current, device):
+ for sid in get_sessions_to_clear(user, keep_current):
delete_session(sid, reason=reason)
-def get_sessions_to_clear(user=None, keep_current=False, device=None):
+def get_sessions_to_clear(user=None, keep_current=False):
"""Returns sessions of the current user. Called at login / logout
:param user: user name (default: current user)
:param keep_current: keep current session (default: false)
- :param device: delete sessions of this device (default: desktop, mobile)
"""
if not user:
user = frappe.session.user
- if not device:
- device = ("desktop", "mobile")
-
- if not isinstance(device, (tuple, list)):
- device = (device,)
-
offset = 0
if user == frappe.session.user:
simultaneous_sessions = frappe.db.get_value("User", user, "simultaneous_sessions") or 1
offset = simultaneous_sessions - 1
session = DocType("Sessions")
- session_id = frappe.qb.from_(session).where(
- (session.user == user) & (session.device.isin(device))
- )
+ session_id = frappe.qb.from_(session).where(session.user == user)
if keep_current:
session_id = session_id.where(session.sid != frappe.session.sid)
@@ -121,25 +111,18 @@ def clear_all_sessions(reason=None):
def get_expired_sessions():
"""Returns list of expired sessions"""
+
sessions = DocType("Sessions")
- expired = []
- for device in ("desktop", "mobile"):
- expired.extend(
- frappe.db.get_values(
- sessions,
- filters=(
- PseudoColumn(f"({Now()} - {sessions.lastupdate.get_sql()})")
- > get_expiry_period_for_query(device)
- )
- & (sessions.device == device),
- fieldname="sid",
- order_by=None,
- pluck=True,
- )
- )
-
- return expired
+ return frappe.db.get_values(
+ sessions,
+ filters=(
+ PseudoColumn(f"({Now()} - {sessions.lastupdate.get_sql()})") > get_expiry_period_for_query()
+ ),
+ fieldname="sid",
+ order_by=None,
+ pluck=True,
+ )
def clear_expired_sessions():
@@ -218,14 +201,13 @@ def generate_csrf_token():
class Session:
- __slots__ = ("user", "device", "user_type", "full_name", "data", "time_diff", "sid")
+ __slots__ = ("user", "user_type", "full_name", "data", "time_diff", "sid")
def __init__(self, user, resume=False, full_name=None, user_type=None):
self.sid = cstr(
frappe.form_dict.get("sid") or unquote(frappe.request.cookies.get("sid", "Guest"))
)
self.user = user
- self.device = frappe.form_dict.get("device") or "desktop"
self.user_type = user_type
self.full_name = full_name
self.data = frappe._dict({"data": frappe._dict({})})
@@ -257,10 +239,9 @@ class Session:
self.data.data.update(
{
"last_updated": frappe.utils.now(),
- "session_expiry": get_expiry_period(self.device),
+ "session_expiry": get_expiry_period(),
"full_name": self.full_name,
"user_type": self.user_type,
- "device": self.device,
"session_country": get_geo_ip_country(frappe.local.request_ip)
if frappe.local.request_ip
else None,
@@ -289,9 +270,9 @@ class Session:
def insert_session_record(self):
frappe.db.sql(
"""insert into `tabSessions`
- (`sessiondata`, `user`, `lastupdate`, `sid`, `status`, `device`)
- values (%s , %s, NOW(), %s, 'Active', %s)""",
- (str(self.data["data"]), self.data["user"], self.data["sid"], self.device),
+ (`sessiondata`, `user`, `lastupdate`, `sid`, `status`)
+ values (%s , %s, NOW(), %s, 'Active')""",
+ (str(self.data["data"]), self.data["user"], self.data["sid"]),
)
# also add to memcache
@@ -308,7 +289,6 @@ class Session:
self.data.update({"data": data, "user": data.user, "sid": self.sid})
self.user = data.user
validate_ip_address(self.user)
- self.device = data.device
else:
self.start_as_guest()
@@ -359,22 +339,11 @@ class Session:
def get_session_data_from_db(self):
sessions = DocType("Sessions")
-
- self.device = (
- frappe.db.get_value(
- sessions,
- filters=sessions.sid == self.sid,
- fieldname="device",
- order_by=None,
- )
- or "desktop"
- )
rec = frappe.db.get_values(
sessions,
filters=(sessions.sid == self.sid)
& (
- PseudoColumn(f"({Now()} - {sessions.lastupdate.get_sql()})")
- < get_expiry_period_for_query(self.device)
+ PseudoColumn(f"({Now()} - {sessions.lastupdate.get_sql()})") < get_expiry_period_for_query()
),
fieldname=["user", "sessiondata"],
order_by=None,
@@ -437,29 +406,23 @@ class Session:
return updated_in_db
-def get_expiry_period_for_query(device=None):
+def get_expiry_period_for_query():
if frappe.db.db_type == "postgres":
- return get_expiry_period(device)
+ return get_expiry_period()
else:
- return get_expiry_in_seconds(device=device)
+ return get_expiry_in_seconds()
-def get_expiry_in_seconds(expiry=None, device=None):
+def get_expiry_in_seconds(expiry=None):
if not expiry:
- expiry = get_expiry_period(device)
+ expiry = get_expiry_period()
+
parts = expiry.split(":")
return (cint(parts[0]) * 3600) + (cint(parts[1]) * 60) + cint(parts[2])
-def get_expiry_period(device="desktop"):
- if device == "mobile":
- key = "session_expiry_mobile"
- default = "720:00:00"
- else:
- key = "session_expiry"
- default = "06:00:00"
-
- exp_sec = frappe.defaults.get_global_default(key) or default
+def get_expiry_period():
+ exp_sec = frappe.defaults.get_global_default("session_expiry") or "06:00:00"
# incase seconds is missing
if len(exp_sec.split(":")) == 2:
diff --git a/frappe/templates/includes/login/login.js b/frappe/templates/includes/login/login.js
index 8365947e6c..60dd0396de 100644
--- a/frappe/templates/includes/login/login.js
+++ b/frappe/templates/includes/login/login.js
@@ -19,7 +19,6 @@ login.bind_events = function () {
args.cmd = "login";
args.usr = frappe.utils.xss_sanitise(($("#login_email").val() || "").trim());
args.pwd = $("#login_password").val();
- args.device = "desktop";
if (!args.usr || !args.pwd) {
frappe.msgprint('{{ _("Both login and password required") }}');
return false;
@@ -73,7 +72,6 @@ login.bind_events = function () {
args.cmd = "{{ ldap_settings.method }}";
args.usr = ($("#login_email").val() || "").trim();
args.pwd = $("#login_password").val();
- args.device = "desktop";
if (!args.usr || !args.pwd) {
login.set_status('{{ _("Both login and password required") }}', 'red');
return false;
diff --git a/frappe/test_runner.py b/frappe/test_runner.py
index 7e2c7e724f..3876d065b1 100644
--- a/frappe/test_runner.py
+++ b/frappe/test_runner.py
@@ -148,11 +148,11 @@ def set_test_email_config():
class TimeLoggingTestResult(unittest.TextTestResult):
def startTest(self, test):
- self._started_at = time.time()
+ self._started_at = time.monotonic()
super().startTest(test)
def addSuccess(self, test):
- elapsed = time.time() - self._started_at
+ elapsed = time.monotonic() - self._started_at
name = self.getDescription(test)
if elapsed >= SLOW_TEST_THRESHOLD:
self.stream.write(f"\n{name} ({elapsed:.03}s)\n")
diff --git a/frappe/tests/test_document.py b/frappe/tests/test_document.py
index 4ad2d85a19..474971c935 100644
--- a/frappe/tests/test_document.py
+++ b/frappe/tests/test_document.py
@@ -424,6 +424,30 @@ class TestDocument(FrappeTestCase):
self.assertRaises(frappe.DoesNotExistError, doc.save)
+ def test_validate_from_to_dates(self):
+ doc = frappe.new_doc("Web Page")
+ doc.start_date = None
+ doc.end_date = None
+ doc.validate_from_to_dates("start_date", "end_date")
+
+ doc.start_date = "2020-01-01"
+ doc.end_date = None
+ doc.validate_from_to_dates("start_date", "end_date")
+
+ doc.start_date = None
+ doc.end_date = "2020-12-31"
+ doc.validate_from_to_dates("start_date", "end_date")
+
+ doc.start_date = "2020-01-01"
+ doc.end_date = "2020-12-31"
+ doc.validate_from_to_dates("start_date", "end_date")
+
+ doc.end_date = "2020-01-01"
+ doc.start_date = "2020-12-31"
+ self.assertRaises(
+ frappe.exceptions.InvalidDates, doc.validate_from_to_dates, "start_date", "end_date"
+ )
+
class TestDocumentWebView(FrappeTestCase):
def get(self, path, user="Guest"):
diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py
index 44966691a0..cf6134d101 100644
--- a/frappe/tests/test_utils.py
+++ b/frappe/tests/test_utils.py
@@ -68,6 +68,7 @@ from frappe.utils.identicon import Identicon
from frappe.utils.image import optimize_image, strip_exif_data
from frappe.utils.make_random import can_make, get_random, how_many
from frappe.utils.response import json_handler
+from frappe.utils.synchronization import LockTimeoutError, filelock
class Capturing(list):
@@ -880,6 +881,22 @@ class TestContainerUtils(FrappeTestCase):
self.assertEqual(a["c"], "d")
+class TestLocks(FrappeTestCase):
+ def test_locktimeout(self):
+ lock_name = "test_lock"
+ with filelock(lock_name):
+ with self.assertRaises(LockTimeoutError):
+ with filelock(lock_name, timeout=1):
+ self.fail("Locks not working")
+
+ def test_global_lock(self):
+ lock_name = "test_global"
+ with filelock(lock_name, is_global=True):
+ with self.assertRaises(LockTimeoutError):
+ with filelock(lock_name, timeout=1, is_global=True):
+ self.fail("Global locks not working")
+
+
class TestMiscUtils(FrappeTestCase):
def test_get_file_timestamp(self):
self.assertIsInstance(get_file_timestamp(__file__), str)
diff --git a/frappe/tests/utils.py b/frappe/tests/utils.py
index 647720a78f..15e0c3d9c0 100644
--- a/frappe/tests/utils.py
+++ b/frappe/tests/utils.py
@@ -22,6 +22,7 @@ class FrappeTestCase(unittest.TestCase):
TEST_SITE = "test_site"
SHOW_TRANSACTION_COMMIT_WARNINGS = False
+ maxDiff = None # prints long diffs but useful in CI
@classmethod
def setUpClass(cls) -> None:
diff --git a/frappe/translations/af.csv b/frappe/translations/af.csv
index 88f30be096..53bb3f1946 100644
--- a/frappe/translations/af.csv
+++ b/frappe/translations/af.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Is Submittable,
Is Table,Is Tabel,
Is Your Company Address,Is u maatskappy se adres,
It is risky to delete this file: {0}. Please contact your System Manager.,Dit is riskant om hierdie lêer te verwyder: {0}. Kontak asseblief u stelselbestuurder.,
-Item cannot be added to its own descendents,Item kan nie by sy eie afstammelinge bygevoeg word nie,
+Item cannot be added to its own descendants,Item kan nie by sy eie afstammelinge bygevoeg word nie,
JS,JS,
JSON,into,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript-formaat: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/am.csv b/frappe/translations/am.csv
index 5321621e03..34856d1a6b 100644
--- a/frappe/translations/am.csv
+++ b/frappe/translations/am.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable ነው,
Is Table,ማውጫ ነው,
Is Your Company Address,የእርስዎ ኩባንያ አድራሻ ነው,
It is risky to delete this file: {0}. Please contact your System Manager.,ይህ ፋይል መሰረዝ አደገኛ ነው: {0}. እባክዎ የስርዓት አስተዳዳሪዎን ያግኙ.,
-Item cannot be added to its own descendents,ንጥል የራሱን ዘር ሊታከሉ አይችሉም,
+Item cannot be added to its own descendants,ንጥል የራሱን ዘር ሊታከሉ አይችሉም,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},ጃቫስክሪፕት ቅርጸት: frappe.query_reports [ 'REPORTNAME'] = {},
diff --git a/frappe/translations/ar.csv b/frappe/translations/ar.csv
index 95caebd35f..d712576ebd 100644
--- a/frappe/translations/ar.csv
+++ b/frappe/translations/ar.csv
@@ -1395,7 +1395,7 @@ Is Submittable,يستطيع الاعتماد,
Is Table,هو الجدول,
Is Your Company Address,يكون عنوان شركتك,
It is risky to delete this file: {0}. Please contact your System Manager.,أنه أمر محفوف بالمخاطر لحذف هذا الملف: {0}. يرجى الاتصال بمدير النظام الخاص بك.,
-Item cannot be added to its own descendents,البند لا يمكن أن تضاف الى أحفادها
Item cannot be added to its own descendents,
+Item cannot be added to its own descendants,البند لا يمكن أن تضاف الى أحفادها
Item cannot be added to its own descendants,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},جافا سكريبت الصيغة: frappe.query_reports [' REPORTNAME '] = { },
diff --git a/frappe/translations/bg.csv b/frappe/translations/bg.csv
index 553b9eab13..6ac12e9f0e 100644
--- a/frappe/translations/bg.csv
+++ b/frappe/translations/bg.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Дали Правят,
Is Table,Е таблица,
Is Your Company Address,Вашата компания Адрес,
It is risky to delete this file: {0}. Please contact your System Manager.,"Рисковано е да изтриете този файл: {0}. Моля, обърнете се към вашия System Manager.",
-Item cannot be added to its own descendents,Позицията не може да бъде добавена към собствените си потомци,
+Item cannot be added to its own descendants,Позицията не може да бъде добавена към собствените си потомци,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Формат: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/bn.csv b/frappe/translations/bn.csv
index b6465fc555..a22149cbff 100644
--- a/frappe/translations/bn.csv
+++ b/frappe/translations/bn.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable হয়,
Is Table,টেবিল,
Is Your Company Address,আপনার কোম্পানির ঠিকানা,
It is risky to delete this file: {0}. Please contact your System Manager.,এটা এই ফাইলটি মোছার জন্য ঝুঁকিপূর্ণ: {0}. আপনার সিস্টেম ম্যানেজার সাথে যোগাযোগ করুন.,
-Item cannot be added to its own descendents,আইটেমটি নিজস্ব সন্তান যোগ করা যাবে না,
+Item cannot be added to its own descendants,আইটেমটি নিজস্ব সন্তান যোগ করা যাবে না,
JS,js,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},জাভাস্ক্রিপ্ট বিন্যাস: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/bs.csv b/frappe/translations/bs.csv
index 9ddb78dfe0..d691d770ed 100644
--- a/frappe/translations/bs.csv
+++ b/frappe/translations/bs.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Je Submittable,
Is Table,je Tabela,
Is Your Company Address,Is Your Company Adresa,
It is risky to delete this file: {0}. Please contact your System Manager.,To je rizično izbrisati ovu datoteku: {0}. Molimo vas da se obratite System Manager.,
-Item cannot be added to its own descendents,Stavka ne može se dodati u svojim potomcima,
+Item cannot be added to its own descendants,Stavka ne može se dodati u svojim potomcima,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript format : frappe.query_reports [ ' REPORTNAME ' ] = { },
diff --git a/frappe/translations/ca.csv b/frappe/translations/ca.csv
index 3de89a8620..39aca480f4 100644
--- a/frappe/translations/ca.csv
+++ b/frappe/translations/ca.csv
@@ -1395,7 +1395,7 @@ Is Submittable,És submittable,
Is Table,és Taula,
Is Your Company Address,La seva adreça és l'empresa,
It is risky to delete this file: {0}. Please contact your System Manager.,"És arriscat eliminar aquesta imatge: {0}. Si us plau, poseu-vos en contacte amb l'administrador del sistema.",
-Item cannot be added to its own descendents,L'article no es pot afegir als seus propis descendents,
+Item cannot be added to its own descendants,L'article no es pot afegir als seus propis descendants,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports['REPORTNAME'] = {},
@@ -1675,7 +1675,7 @@ No {0} permission,No {0} permís,
None: End of Workflow,Cap: Final de flux de treball,
Not Allowed: Disabled User,No permès: usuari desactivat,
Not Ancestors Of,Sense avantpassats de,
-Not Descendants Of,Sense descendents de,
+Not Descendants Of,Sense descendants de,
Not Equals,No Equival,
Not In,No En,
Not Linked to any record,No vinculats a cap registre,
@@ -3045,7 +3045,7 @@ zoom-out,menys-zoom,
{0} has been successfully added to the Email Group.,{0} s'ha afegit al Grup de Correu Electrònic.,
{0} has left the conversation in {1} {2},{0} ha deixat la conversa en {1} {2},
{0} hours ago,Fa {0} hores,
-{0} in row {1} cannot have both URL and child items,{0} a la fila {1} no pot tenir les dues coses URL i elements descendents,
+{0} in row {1} cannot have both URL and child items,{0} a la fila {1} no pot tenir les dues coses URL i elements descendants,
{0} is a mandatory field,{0} és un camp obligatori,
{0} is an invalid email address in 'Recipients',{0} és una adreça electrònica no vàlida a "Destinataris",
{0} is not a raw printing format.,{0} no és un format d'impressió en brut.,
@@ -3086,7 +3086,7 @@ zoom-out,menys-zoom,
{0} {1} added,S'ha afegit {0} {1},
{0} {1} already exists,{0} {1} ja existeix,
"{0} {1} cannot be ""{2}"". It should be one of ""{3}""","{0} {1} no pot ser ""{2}"". Ha de ser un de ""{3}""",
-{0} {1} cannot be a leaf node as it has children,{0} {1} no pot ser un node fulla perquè té descendents,
+{0} {1} cannot be a leaf node as it has children,{0} {1} no pot ser un node fulla perquè té descendants,
"{0} {1} does not exist, select a new target to merge","{0} {1} no existeix, seleccioneu un nou objectiu per unir",
{0} {1} not found,{0} {1} no trobat,
{0} {1} to {2},{0} {1} a {2},
diff --git a/frappe/translations/cs.csv b/frappe/translations/cs.csv
index 262d8bb1e5..0c35b6eaa1 100644
--- a/frappe/translations/cs.csv
+++ b/frappe/translations/cs.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Je Odeslatelné,
Is Table,je Tabulka,
Is Your Company Address,Je vaše firma adresa,
It is risky to delete this file: {0}. Please contact your System Manager.,"Je to riskantní smazat tento soubor: {0}. Prosím, obraťte se na správce systému.",
-Item cannot be added to its own descendents,Položka nemůže být přidána jako svůj vlastní podřízený potomek,
+Item cannot be added to its own descendants,Položka nemůže být přidána jako svůj vlastní podřízený potomek,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Formát: frappe.query_reports['REPORTNAME'] = {},
diff --git a/frappe/translations/cz.csv b/frappe/translations/cz.csv
index 818d2b2d9e..de01db0a29 100644
--- a/frappe/translations/cz.csv
+++ b/frappe/translations/cz.csv
@@ -850,7 +850,7 @@ DocType: Workflow State,trash,koš
apps/frappe/frappe/desk/page/activity/activity.js +153,Dec,Pro
DocType: Event,Leave blank to repeat always,Nechte prázdné pro opakování vždy
DocType: Event,Ends on,Končí
-apps/frappe/frappe/utils/nestedset.py +181,Item cannot be added to its own descendents,Položka nemůže být přidána jako svůj vlastní podřízený potomek
+apps/frappe/frappe/utils/nestedset.py +181,Item cannot be added to its own descendants,Položka nemůže být přidána jako svůj vlastní podřízený potomek
sites/assets/js/form.min.js +270,{0} created this {1},{0} vytvoření této {1}
apps/frappe/frappe/desk/form/assign_to.py +120,"The task {0}, that you assigned to {1}, has been closed by {2}.","Úkol {0}, které jste přiřadili k {1}, bylo uzavřeno {2}."
DocType: Blogger,Short Name,Zkrácené jméno
diff --git a/frappe/translations/da.csv b/frappe/translations/da.csv
index 8a6398986c..c2cc077aac 100644
--- a/frappe/translations/da.csv
+++ b/frappe/translations/da.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Kan godkendes,
Is Table,er Table,
Is Your Company Address,Er din virksomhedsadresse,
It is risky to delete this file: {0}. Please contact your System Manager.,Det er risikabelt at slette denne fil: {0}. Kontakt din systemadministrator.,
-Item cannot be added to its own descendents,Punkt kan ikke føjes til sine egne efterkommere,
+Item cannot be added to its own descendants,Punkt kan ikke føjes til sine egne efterkommere,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports ['rapportnavn'] = {},
diff --git a/frappe/translations/de.csv b/frappe/translations/de.csv
index 6cd8133f94..fd81f8e87c 100644
--- a/frappe/translations/de.csv
+++ b/frappe/translations/de.csv
@@ -1404,7 +1404,7 @@ Is Table,ist eine Tabelle,
Is Template, Ist Vorlage,
Is Your Company Address,Ist Ihre Unternehmensadresse,
It is risky to delete this file: {0}. Please contact your System Manager.,"Es ist riskant, diese Datei zu löschen: {0}. Bitte kontaktieren Sie Ihren System-Manager.",
-Item cannot be added to its own descendents,Artikel kann nicht zu seinen eigenen Abkömmlingen hinzugefügt werden,
+Item cannot be added to its own descendants,Artikel kann nicht zu seinen eigenen Abkömmlingen hinzugefügt werden,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript- Format: frappe.query_reports [' REPORT '] = {},
diff --git a/frappe/translations/el.csv b/frappe/translations/el.csv
index d966526e44..e6bfe4eb5b 100644
--- a/frappe/translations/el.csv
+++ b/frappe/translations/el.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Είναι υποβλητέο,
Is Table,είναι πίνακας,
Is Your Company Address,Η εταιρεία σας Διεύθυνση,
It is risky to delete this file: {0}. Please contact your System Manager.,Είναι επικίνδυνο να διαγράψετε αυτό το αρχείο: {0}. Επικοινωνήστε με το διαχειριστή του συστήματός σας.,
-Item cannot be added to its own descendents,Το είδος δεν μπορεί να προστεθεί στους δικούς του απογόνους,
+Item cannot be added to its own descendants,Το είδος δεν μπορεί να προστεθεί στους δικούς του απογόνους,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports['REPORTNAME'] = {},
diff --git a/frappe/translations/es.csv b/frappe/translations/es.csv
index 0e88b7c2be..997ee859a5 100644
--- a/frappe/translations/es.csv
+++ b/frappe/translations/es.csv
@@ -1409,7 +1409,7 @@ Is Submittable,Se puede validar,
Is Table,es Tabla,
Is Your Company Address,Es la Dirección de su Compañia,
It is risky to delete this file: {0}. Please contact your System Manager.,"Es arriesgado eliminar este archivo: {0}. Por favor, póngase en contacto con el administrador del sistema.",
-Item cannot be added to its own descendents,El producto no se puede añadir a sus propios heredados,
+Item cannot be added to its own descendants,El producto no se puede añadir a sus propios heredados,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Formato de JavaScript: : frappe.query_reports['REPORTNAME'] = {},
diff --git a/frappe/translations/et.csv b/frappe/translations/et.csv
index c4ca980045..9bd1f6e829 100644
--- a/frappe/translations/et.csv
+++ b/frappe/translations/et.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Kas esitatav,
Is Table,Kas tabelis,
Is Your Company Address,Kas teie firma Aadress,
It is risky to delete this file: {0}. Please contact your System Manager.,See on riskantne kustutada seda faili: {0}. Palun võtke System Manager.,
-Item cannot be added to its own descendents,Punkt ei saa lisada oma järeltulijad,
+Item cannot be added to its own descendants,Punkt ei saa lisada oma järeltulijad,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Formaat: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/fa.csv b/frappe/translations/fa.csv
index 99df9a9dca..0509056542 100644
--- a/frappe/translations/fa.csv
+++ b/frappe/translations/fa.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable است,
Is Table,است جدول,
Is Your Company Address,آیا شرکت شما در نشانی,
It is risky to delete this file: {0}. Please contact your System Manager.,این خطرناک است این فایل را حذف کنید: {0}. لطفا با مدیر سیستم تماس بگیرید.,
-Item cannot be added to its own descendents,مورد می تواند به بازماندگان خود را اضافه نمی شوند,
+Item cannot be added to its own descendants,مورد می تواند به بازماندگان خود را اضافه نمی شوند,
JS,جی اس,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},جاوا اسکریپت فرمت: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/fi.csv b/frappe/translations/fi.csv
index 2c62458fbb..0de73aca37 100644
--- a/frappe/translations/fi.csv
+++ b/frappe/translations/fi.csv
@@ -1395,7 +1395,7 @@ Is Submittable,On vahvistettavissa,
Is Table,taulukkomuotoinen,
Is Your Company Address,Is Your Company Osoite,
It is risky to delete this file: {0}. Please contact your System Manager.,Se on riskialtista poistaa tiedoston: {0}. Ota yhteyttä System Manager.,
-Item cannot be added to its own descendents,tuotetta ei voi lisätä omaksi alatuotteekseen,
+Item cannot be added to its own descendants,tuotetta ei voi lisätä omaksi alatuotteekseen,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},formaatti JavaScript: frappe.query_reports ['raportin_nimi'] = {},
diff --git a/frappe/translations/fr.csv b/frappe/translations/fr.csv
index da330d3534..9a1e4350c0 100644
--- a/frappe/translations/fr.csv
+++ b/frappe/translations/fr.csv
@@ -1397,7 +1397,7 @@ Is Submittable,Est Validable,
Is Table,Est Table,
Is Your Company Address,Est l'Adresse de votre Entreprise,
It is risky to delete this file: {0}. Please contact your System Manager.,Il est risqué de supprimer ce fichier : {0}. Veuillez contactez votre Administrateur Système.,
-Item cannot be added to its own descendents,L'article ne peut être ajouté à ses propres descendants,
+Item cannot be added to its own descendants,L'article ne peut être ajouté à ses propres descendants,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},"""Format JavaScript :\nfrappe.query_reports [' NOMDURAPPORT '] = {}""",
diff --git a/frappe/translations/gu.csv b/frappe/translations/gu.csv
index e13637d26a..1eeeb813a9 100644
--- a/frappe/translations/gu.csv
+++ b/frappe/translations/gu.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable છે,
Is Table,ટેબલ છે,
Is Your Company Address,તમારી કંપની સરનામું,
It is risky to delete this file: {0}. Please contact your System Manager.,તે આ ફાઇલ કાઢી જોખમી છે: {0}. તમારી સિસ્ટમ મેનેજરનો સંપર્ક કરો.,
-Item cannot be added to its own descendents,આઇટમ તેના પોતાના વંશજ ઉમેરવામાં કરી શકાતી નથી,
+Item cannot be added to its own descendants,આઇટમ તેના પોતાના વંશજ ઉમેરવામાં કરી શકાતી નથી,
JS,જેએસ,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},જાવાસ્ક્રિપ્ટ ફોર્મેટ: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/he.csv b/frappe/translations/he.csv
index dda9f2b233..d7e06060a8 100644
--- a/frappe/translations/he.csv
+++ b/frappe/translations/he.csv
@@ -1395,7 +1395,7 @@ Is Submittable,האם Submittable,
Is Table,האם לוח,
Is Your Company Address,האם כתובת החברה שלך,
It is risky to delete this file: {0}. Please contact your System Manager.,זה מסוכן כדי למחוק קובץ זה: {0}. אנא צור קשר עם מנהל המערכת שלך.,
-Item cannot be added to its own descendents,פריט לא ניתן להוסיף לצאצאים משלו,
+Item cannot be added to its own descendants,פריט לא ניתן להוסיף לצאצאים משלו,
JS,Js,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},פורמט JavaScript: frappe.query_reports ['את REPORTTYPE'] = {},
diff --git a/frappe/translations/hi.csv b/frappe/translations/hi.csv
index fcf3a32263..d5a8119145 100644
--- a/frappe/translations/hi.csv
+++ b/frappe/translations/hi.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable है,
Is Table,टेबल है,
Is Your Company Address,आपकी कंपनी पता है,
It is risky to delete this file: {0}. Please contact your System Manager.,यह इस फ़ाइल को नष्ट करने के लिए जोखिम भरा है: {0}। अपने सिस्टम मैनेजर से संपर्क करें।,
-Item cannot be added to its own descendents,आइटम अपने खुद के वंशजों को जोड़ा नहीं जा सकता,
+Item cannot be added to its own descendants,आइटम अपने खुद के वंशजों को जोड़ा नहीं जा सकता,
JS,जे एस,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},जावास्क्रिप्ट स्वरूप: frappe.query_reports [' REPORTNAME '] = {},
diff --git a/frappe/translations/hr.csv b/frappe/translations/hr.csv
index 4846876c82..3f2dfe1065 100644
--- a/frappe/translations/hr.csv
+++ b/frappe/translations/hr.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Je Submittable,
Is Table,je Tablica,
Is Your Company Address,Je li Vaše poduzeće adresa,
It is risky to delete this file: {0}. Please contact your System Manager.,To je rizično izbrisati ovu datoteku: {0}. Molimo kontaktirajte svog sustava Manageru.,
-Item cannot be added to its own descendents,Proizvod ne može se dodati u svojim potomcima,
+Item cannot be added to its own descendants,Proizvod ne može se dodati u svojim potomcima,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript format : frappe.query_reports [ ' REPORTNAME ' ] = { },
diff --git a/frappe/translations/hu.csv b/frappe/translations/hu.csv
index 677447b809..7e5b9b3c36 100644
--- a/frappe/translations/hu.csv
+++ b/frappe/translations/hu.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Ez küldhető,
Is Table,Ez táblázat,
Is Your Company Address,Az Ön cége címe,
It is risky to delete this file: {0}. Please contact your System Manager.,"Kockázatos törölni ezt a fájlt: {0}. Kérjük, forduljon a Rendszergazdához.",
-Item cannot be added to its own descendents,Tételt nem lehet hozzáadni a saját leszármazottaikhoz,
+Item cannot be added to its own descendants,Tételt nem lehet hozzáadni a saját leszármazottaikhoz,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports ['JELENTÉSNÉV'] = {},
diff --git a/frappe/translations/id.csv b/frappe/translations/id.csv
index ff46ec82a9..8b39cd0c5c 100644
--- a/frappe/translations/id.csv
+++ b/frappe/translations/id.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Apakah Submittable,
Is Table,Apakah Tabel,
Is Your Company Address,Apakah Alamat Perusahaan Anda,
It is risky to delete this file: {0}. Please contact your System Manager.,Hal ini berisiko untuk menghapus file ini: {0}. Silahkan hubungi System Manager Anda.,
-Item cannot be added to its own descendents,Item tidak dapat ditambahkan ke keturunan sendiri,
+Item cannot be added to its own descendants,Item tidak dapat ditambahkan ke keturunan sendiri,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/is.csv b/frappe/translations/is.csv
index f870b63254..bc6dab989a 100644
--- a/frappe/translations/is.csv
+++ b/frappe/translations/is.csv
@@ -1395,7 +1395,7 @@ Is Submittable,er Submittable,
Is Table,er Tafla,
Is Your Company Address,Er fyrirtækið Heimilisfang þitt,
It is risky to delete this file: {0}. Please contact your System Manager.,Það er áhættusamt að eyða þessari skrá: {0}. Vinsamlegast hafðu samband System Manager.,
-Item cannot be added to its own descendents,Atriði er ekki hægt að bæta við eigin afkomenda sinna,
+Item cannot be added to its own descendants,Atriði er ekki hægt að bæta við eigin afkomenda sinna,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports [ 'REPORTNAME'] = {},
diff --git a/frappe/translations/it.csv b/frappe/translations/it.csv
index 3a46044681..99c0bae9b8 100644
--- a/frappe/translations/it.csv
+++ b/frappe/translations/it.csv
@@ -1395,7 +1395,7 @@ Is Submittable,È Confermabile,
Is Table,è Tabella,
Is Your Company Address,È il vostro indirizzo azienda,
It is risky to delete this file: {0}. Please contact your System Manager.,E' rischioso cancellare questo file: {0}. Si prega di contattare il Responsabile di Sistema.,
-Item cannot be added to its own descendents,L'articolo non può essere aggiunto ai propri discendenti,
+Item cannot be added to its own descendants,L'articolo non può essere aggiunto ai propri discendenti,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Formato JavaScript: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/ja.csv b/frappe/translations/ja.csv
index 8a1e3d0884..460dd4a4b9 100644
--- a/frappe/translations/ja.csv
+++ b/frappe/translations/ja.csv
@@ -1395,7 +1395,7 @@ Is Submittable,提出可能,
Is Table,表,
Is Your Company Address,あなたの会社の住所,
It is risky to delete this file: {0}. Please contact your System Manager.,このファイル {0} を削除することは危険です。システム管理者にお問い合わせください。,
-Item cannot be added to its own descendents,アイテムは自身の子孫に追加することはできません,
+Item cannot be added to its own descendants,アイテムは自身の子孫に追加することはできません,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript形式:frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/km.csv b/frappe/translations/km.csv
index 6b7ad32f40..73c0b2b27e 100644
--- a/frappe/translations/km.csv
+++ b/frappe/translations/km.csv
@@ -1395,7 +1395,7 @@ Is Submittable,តើការ Submittable,
Is Table,គឺជាតារាង,
Is Your Company Address,គឺជាអាសយដ្ឋានក្រុមហ៊ុនរបស់អ្នក,
It is risky to delete this file: {0}. Please contact your System Manager.,វាគឺជាការប្រថុយប្រថានក្នុងការលុបឯកសារនេះ: {0} ។ សូមទាក់ទងកម្មវិធីគ្រប់គ្រងប្រព័ន្ធរបស់អ្នក។,
-Item cannot be added to its own descendents,ធាតុមិនអាចត្រូវបានបន្ថែមទៅជនជាតិផ្ទាល់របស់ខ្លួន,
+Item cannot be added to its own descendants,ធាតុមិនអាចត្រូវបានបន្ថែមទៅជនជាតិផ្ទាល់របស់ខ្លួន,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript ទ្រង់ទ្រាយ: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/kn.csv b/frappe/translations/kn.csv
index ef5e06a016..68f4a6cf18 100644
--- a/frappe/translations/kn.csv
+++ b/frappe/translations/kn.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable ಈಸ್,
Is Table,ಟೇಬಲ್,
Is Your Company Address,ನಿಮ್ಮ ಕಂಪನಿ ವಿಳಾಸ,
It is risky to delete this file: {0}. Please contact your System Manager.,ಇದು ಈ ಕಡತ ಅಳಿಸಲು ಅಪಾಯಕಾರಿ: {0}. ನಿಮ್ಮ ಸಿಸ್ಟಂ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.,
-Item cannot be added to its own descendents,ಐಟಂ ತನ್ನದೇ ಸಂತತಿಯವರು ಸೇರಿಸಲಾಗಿದೆ ಸಾಧ್ಯವಿಲ್ಲ,
+Item cannot be added to its own descendants,ಐಟಂ ತನ್ನದೇ ಸಂತತಿಯವರು ಸೇರಿಸಲಾಗಿದೆ ಸಾಧ್ಯವಿಲ್ಲ,
JS,ಉಪಯೋಗಿಸಿದ,
JSON,JSON ಅನ್ನು,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಫಾರ್ಮ್ಯಾಟ್: frappe.query_reports [ 'ವರದಿಯನ್ನು ಹೆಸರು '] = {},
diff --git a/frappe/translations/ko.csv b/frappe/translations/ko.csv
index a40c2b787d..d5f2ace782 100644
--- a/frappe/translations/ko.csv
+++ b/frappe/translations/ko.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable입니다,
Is Table,표입니다,
Is Your Company Address,귀하의 회사 주소입니다,
It is risky to delete this file: {0}. Please contact your System Manager.,그것은이 파일을 삭제하는 위험 : {0}. 시스템 관리자에게 문의하시기 바랍니다.,
-Item cannot be added to its own descendents,항목은 자체 하위에 추가 할 수없는,
+Item cannot be added to its own descendants,항목은 자체 하위에 추가 할 수없는,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},자바 스크립트 형식 : frappe.query_reports [ 'REPORTNAME'] = {},
diff --git a/frappe/translations/ku.csv b/frappe/translations/ku.csv
index a30ffc115d..e9fde50046 100644
--- a/frappe/translations/ku.csv
+++ b/frappe/translations/ku.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable e,
Is Table,e Table,
Is Your Company Address,E Company te Address,
It is risky to delete this file: {0}. Please contact your System Manager.,Ev metirsiyek e li vê pelê jê bibî: {0}. Ji kerema xwe ve Manager Pergala xwe re bikeve têkiliyê.,
-Item cannot be added to its own descendents,Babetê dikarin ji bo neviyên xwe bi xwe ne bê added,
+Item cannot be added to its own descendants,Babetê dikarin ji bo neviyên xwe bi xwe ne bê added,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports [ 'REPORTNAME'] = {},
diff --git a/frappe/translations/lo.csv b/frappe/translations/lo.csv
index fceaa5a31f..b48f7b3e71 100644
--- a/frappe/translations/lo.csv
+++ b/frappe/translations/lo.csv
@@ -1395,7 +1395,7 @@ Is Submittable,ແມ່ນສົ່ງ,
Is Table,ເປັນຕາຕະລາງ,
Is Your Company Address,ທີ່ຢູ່ຂອງບໍລິສັດ,
It is risky to delete this file: {0}. Please contact your System Manager.,ມັນເປັນຄວາມສ່ຽງສູງທີ່ຈະລຶບເອກະສານນີ້:. {0} ກະລຸນາຕິດຕໍ່ຈັດການລະບົບຂອງທ່ານ.,
-Item cannot be added to its own descendents,ລາຍການບໍ່ສາມາດໄດ້ຮັບການເພີ່ມລູກຫລານຂອງຕົນເອງ,
+Item cannot be added to its own descendants,ລາຍການບໍ່ສາມາດໄດ້ຮັບການເພີ່ມລູກຫລານຂອງຕົນເອງ,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports [ 'REPORTNAME'] = {},
diff --git a/frappe/translations/lt.csv b/frappe/translations/lt.csv
index 22979f9b69..071a7cd2d7 100644
--- a/frappe/translations/lt.csv
+++ b/frappe/translations/lt.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Ar Submittable,
Is Table,Ar lentelė,
Is Your Company Address,Ar Jūsų įmonė Adresas,
It is risky to delete this file: {0}. Please contact your System Manager.,Tai rizikinga ištrinti šį failą: {0}. Prašome susisiekti su savo sistemos valdytojas.,
-Item cannot be added to its own descendents,Prekė negali būti įtraukta į savo palikuonims,
+Item cannot be added to its own descendants,Prekė negali būti įtraukta į savo palikuonims,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Formatas: frappe.query_reports [ 'REPORTNAME'] = {},
diff --git a/frappe/translations/lv.csv b/frappe/translations/lv.csv
index 1b14a6c5da..48c773b620 100644
--- a/frappe/translations/lv.csv
+++ b/frappe/translations/lv.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Vai Submittable,
Is Table,ir tabula,
Is Your Company Address,Vai Jūsu uzņēmuma adrese,
It is risky to delete this file: {0}. Please contact your System Manager.,"Tas ir riskanti, lai izdzēstu šo failu: {0}. Lūdzu, sazinieties ar sistēmas pārzini.",
-Item cannot be added to its own descendents,Posteni nevar pievienot saviem pēcnācējiem,
+Item cannot be added to its own descendants,Posteni nevar pievienot saviem pēcnācējiem,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Formāts: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/mk.csv b/frappe/translations/mk.csv
index 6d171823fb..e045e30c72 100644
--- a/frappe/translations/mk.csv
+++ b/frappe/translations/mk.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Е Submittable,
Is Table,е маса,
Is Your Company Address,Дали вашата компанија адреса,
It is risky to delete this file: {0}. Please contact your System Manager.,Премногу е ризично да ја избришете оваа датотека: {0}. Контактирајте со вашиот систем менаџер.,
-Item cannot be added to its own descendents,Точка не може да се додаде свои потомци,
+Item cannot be added to its own descendants,Точка не може да се додаде свои потомци,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Го вклучите Javascript-формат: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/ml.csv b/frappe/translations/ml.csv
index 6f0a22b53c..ecb4b42874 100644
--- a/frappe/translations/ml.csv
+++ b/frappe/translations/ml.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable Is,
Is Table,മേശ,
Is Your Company Address,നിങ്ങളുടെ കമ്പനി വിലാസമാണ്,
It is risky to delete this file: {0}. Please contact your System Manager.,{0}: അതു ഈ ചിത്രം ഇല്ലാതാക്കാൻ മാറഡോണ. നിങ്ങളുടെ സിസ്റ്റം മാനേജർ ബന്ധപ്പെടുക.,
-Item cannot be added to its own descendents,ഇനം അതിന്റേതായ descendents ചേർക്കില്ല കഴിയില്ല,
+Item cannot be added to its own descendants,ഇനം അതിന്റേതായ descendants ചേർക്കില്ല കഴിയില്ല,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},ജാവാസ്ക്രിപ്റ്റ് ഫോർമാറ്റ്: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/mr.csv b/frappe/translations/mr.csv
index a4d5dadfd6..cbc24e3863 100644
--- a/frappe/translations/mr.csv
+++ b/frappe/translations/mr.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable आहे,
Is Table,टेबल आहे,
Is Your Company Address,आपल्या कंपनीचा पत्ता आहे का ?,
It is risky to delete this file: {0}. Please contact your System Manager.,हि फाइल तुम्ही डिलीट करणे धोकादायक आहे: {0}. तुमची प्रणाली व्यवस्थापकाशी संपर्क साधा.,
-Item cannot be added to its own descendents,आयटम त्याच्या स्वत: च्या descendents ला जोडला जाऊ शकत नाही,
+Item cannot be added to its own descendants,आयटम त्याच्या स्वत: च्या descendants ला जोडला जाऊ शकत नाही,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},जावास्क्रिप्ट स्वरूप: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/ms.csv b/frappe/translations/ms.csv
index c562355b75..e55b860658 100644
--- a/frappe/translations/ms.csv
+++ b/frappe/translations/ms.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Adalah Submittable,
Is Table,adalah Jadual,
Is Your Company Address,Adakah anda Alamat Syarikat,
It is risky to delete this file: {0}. Please contact your System Manager.,Ia adalah berisiko untuk memadam fail ini: {0}. Sila hubungi Pengurus Sistem anda.,
-Item cannot be added to its own descendents,Item tidak boleh ditambah kepada keturunan sendiri,
+Item cannot be added to its own descendants,Item tidak boleh ditambah kepada keturunan sendiri,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/my.csv b/frappe/translations/my.csv
index 724e65e4c5..66951f0f3b 100644
--- a/frappe/translations/my.csv
+++ b/frappe/translations/my.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable ဖြစ်ပါသည်,
Is Table,စားပွဲတင် Is,
Is Your Company Address,သင့်ရဲ့ကုမ္ပဏီလိပ်စာဖြစ်ပါသည်,
It is risky to delete this file: {0}. Please contact your System Manager.,{0}: ဒါဟာဒီဖိုင်ကိုဖျက်ပစ်ရန်အန္တရာယ်များသည်။ သင့်ရဲ့ System ကို Manager ကဆက်သွယ်နိုင်ပါသည်။,
-Item cannot be added to its own descendents,item ၎င်း၏ကိုယ်ပိုင်ဆင်းသက်လာမှဆက်ပြောသည်မရနိုင်ပါ,
+Item cannot be added to its own descendants,item ၎င်း၏ကိုယ်ပိုင်ဆင်းသက်လာမှဆက်ပြောသည်မရနိုင်ပါ,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript ကိုစီစဉ်ဖွဲ့စည်းမှုပုံစံ: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/nl.csv b/frappe/translations/nl.csv
index 677cc279aa..8c11a364a2 100644
--- a/frappe/translations/nl.csv
+++ b/frappe/translations/nl.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Kan ingediend worden,
Is Table,is Table,
Is Your Company Address,Is uw bedrijf Adres,
It is risky to delete this file: {0}. Please contact your System Manager.,Het is riskant om dit bestand te verwijderen: {0}. Neem dan contact op met uw systeembeheerder.,
-Item cannot be added to its own descendents,Artikel kan niet worden toegevoegd aan zijn eigen onderliggende artikelen.,
+Item cannot be added to its own descendants,Artikel kan niet worden toegevoegd aan zijn eigen onderliggende artikelen.,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Formaat : frappe.query_reports ['REPORTNAME'] = { },
diff --git a/frappe/translations/no.csv b/frappe/translations/no.csv
index 03564cc5f2..daa93710e0 100644
--- a/frappe/translations/no.csv
+++ b/frappe/translations/no.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Er Submittable,
Is Table,er Table,
Is Your Company Address,Er din bedrift Adresse,
It is risky to delete this file: {0}. Please contact your System Manager.,Det er risikabelt å slette denne filen: {0}. Ta kontakt med din System Manager.,
-Item cannot be added to its own descendents,Elementet kan ikke legges til sine egne etterkommere,
+Item cannot be added to its own descendants,Elementet kan ikke legges til sine egne etterkommere,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Javascript Format: frappe.query_reports ['rapportnavn'] = {},
diff --git a/frappe/translations/pl.csv b/frappe/translations/pl.csv
index fb2f52179f..e7dd255555 100644
--- a/frappe/translations/pl.csv
+++ b/frappe/translations/pl.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Jest możliwe do przesłania,
Is Table,Czy Table,
Is Your Company Address,Czy Twój adres firmy,
It is risky to delete this file: {0}. Please contact your System Manager.,"To jest ryzykowne, aby usunąć ten plik: {0}. Proszę skontaktować się z System Manager.",
-Item cannot be added to its own descendents,Przedmiot nie może być dodany do własnych potomków,
+Item cannot be added to its own descendants,Przedmiot nie może być dodany do własnych potomków,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Format JavaScript: raporty frappe.query [ 'ReportName'] = {},
diff --git a/frappe/translations/ps.csv b/frappe/translations/ps.csv
index 66380b546a..1911d4a02e 100644
--- a/frappe/translations/ps.csv
+++ b/frappe/translations/ps.csv
@@ -1395,7 +1395,7 @@ Is Submittable,ده Submittable,
Is Table,ده جدول,
Is Your Company Address,آیا ستاسو شرکت پته,
It is risky to delete this file: {0}. Please contact your System Manager.,دا خطرناکه چې د دغې دوتنې د ړنګولو: {0}. لطفا د خپل سیستم د مدیر سره اړیکه.,
-Item cannot be added to its own descendents,د قالب د خپل descendents زياته نه شي,
+Item cannot be added to its own descendants,د قالب د خپل descendants زياته نه شي,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},د جاوا شکل: frappe.query_reports [ 'REPORTNAME'] = {},
diff --git a/frappe/translations/pt-BR.csv b/frappe/translations/pt-BR.csv
index d4dfe920ae..7fd601bfa0 100644
--- a/frappe/translations/pt-BR.csv
+++ b/frappe/translations/pt-BR.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Pode ser Enviado,
Is Table,É Tabela,
Is Your Company Address,É o seu endereço comercial,
It is risky to delete this file: {0}. Please contact your System Manager.,É arriscado excluir este arquivo: {0}. Entre em contato com o administrador do sistema.,
-Item cannot be added to its own descendents,O artigo não pode ser acrescentado para os seus próprios descendentes,
+Item cannot be added to its own descendants,O artigo não pode ser acrescentado para os seus próprios descendentes,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Formato JavaScript: frappe.query_reports [' REPORTNAME '] = {},
diff --git a/frappe/translations/pt.csv b/frappe/translations/pt.csv
index cf4a72e458..0078d6ae7c 100644
--- a/frappe/translations/pt.csv
+++ b/frappe/translations/pt.csv
@@ -1395,7 +1395,7 @@ Is Submittable,É Enviável,
Is Table,É uma Tabela,
Is Your Company Address,É o Seu Endereço Empresarial,
It is risky to delete this file: {0}. Please contact your System Manager.,"É arriscado eliminar este ficheiro: {0}. Por favor, contate o administrador do sistema.",
-Item cannot be added to its own descendents,O item não pode ser acrescentado para aos seus próprios subitens,
+Item cannot be added to its own descendants,O item não pode ser acrescentado para aos seus próprios subitens,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Formato JavaScript:\nfrappe.query_reports['REPORTNAME'] = {},
diff --git a/frappe/translations/ro.csv b/frappe/translations/ro.csv
index 89a7b2edb6..ac20252022 100644
--- a/frappe/translations/ro.csv
+++ b/frappe/translations/ro.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Este Submittable,
Is Table,este Tabelul,
Is Your Company Address,Este Adresa companie,
It is risky to delete this file: {0}. Please contact your System Manager.,Este riscant să ștergeți acest fișier: {0}. Vă rugăm să contactați Managerul de sistem.,
-Item cannot be added to its own descendents,Articol nu poate fi adăugat la propriile descendenți,
+Item cannot be added to its own descendants,Articol nu poate fi adăugat la propriile descendenți,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/ru.csv b/frappe/translations/ru.csv
index bcd02baf93..e508ec2cb8 100644
--- a/frappe/translations/ru.csv
+++ b/frappe/translations/ru.csv
@@ -1391,7 +1391,7 @@ Is Submittable,Подлежит исполнению,
Is Table,Является таблицей,
Is Your Company Address,Является адресом вашей компании,
It is risky to delete this file: {0}. Please contact your System Manager.,"Рискованно удалять этот файл: {0}. Пожалуйста, обратитесь к менеджеру системы.",
-Item cannot be added to its own descendents,Продукт не может быть добавлен к своим подпродуктам,
+Item cannot be added to its own descendants,Продукт не может быть добавлен к своим подпродуктам,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Формат JavaScript: frappe.query_reports ['REPORTNAME'] = {},
Javascript to append to the head section of the page.,Javascript для добавления к головной части страницы.,
John Doe,Джон Доу,
diff --git a/frappe/translations/rw.csv b/frappe/translations/rw.csv
index c33436fd2a..d924c53f2a 100644
--- a/frappe/translations/rw.csv
+++ b/frappe/translations/rw.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Birashoboka,
Is Table,Ni Imbonerahamwe,
Is Your Company Address,Ese Aderesi Yawe,
It is risky to delete this file: {0}. Please contact your System Manager.,Ni bibi gusiba iyi dosiye: {0}. Nyamuneka saba umuyobozi wa sisitemu.,
-Item cannot be added to its own descendents,Ikintu ntigishobora kongerwaho ababakomokaho,
+Item cannot be added to its own descendants,Ikintu ntigishobora kongerwaho ababakomokaho,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Imiterere ya JavaScript: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/si.csv b/frappe/translations/si.csv
index 8ee60ca34f..7af030cf6e 100644
--- a/frappe/translations/si.csv
+++ b/frappe/translations/si.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable වේ,
Is Table,වගුව වේ,
Is Your Company Address,ඔබේ සමාගම ලිපිනය වේ,
It is risky to delete this file: {0}. Please contact your System Manager.,{0}: මෙම ගොනුව මකා දමන්න කිරීම අවදානම් හගත. ඔබේ පද්ධතිය කළමනාකරු හා සම්බන්ධ වන්න.,
-Item cannot be added to its own descendents,අයිතමය තමන්ගේ ම පැවත එන්නන් එකතු කළ නොහැකි,
+Item cannot be added to its own descendants,අයිතමය තමන්ගේ ම පැවත එන්නන් එකතු කළ නොහැකි,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},ජාවාස්ක්රිප්ට් ආකෘතිය: frappe.query_reports [ 'REPORTNAME'] = {},
diff --git a/frappe/translations/sk.csv b/frappe/translations/sk.csv
index d167f710a6..8d3bd829d2 100644
--- a/frappe/translations/sk.csv
+++ b/frappe/translations/sk.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Je Odeslatelné,
Is Table,je Tabuľka,
Is Your Company Address,Je vaša firma adresa,
It is risky to delete this file: {0}. Please contact your System Manager.,"Je to riskantné zmazať tento súbor: {0}. Prosím, obráťte sa na správcu systému.",
-Item cannot be added to its own descendents,Položka nemůže být přidána jako svůj vlastní podřízený potomek,
+Item cannot be added to its own descendants,Položka nemůže být přidána jako svůj vlastní podřízený potomek,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Formát: frappe.query_reports['REPORTNAME'] = {},
diff --git a/frappe/translations/sl.csv b/frappe/translations/sl.csv
index ef6d0aba90..ba3959a523 100644
--- a/frappe/translations/sl.csv
+++ b/frappe/translations/sl.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Je Submittable,
Is Table,je tabela,
Is Your Company Address,Je vaše podjetje naslov,
It is risky to delete this file: {0}. Please contact your System Manager.,To je tvegano izbrisati to datoteko: {0}. Obrnite se na upravitelja sistema.,
-Item cannot be added to its own descendents,Postavka ni mogoče dodati na svoje potomce,
+Item cannot be added to its own descendants,Postavka ni mogoče dodati na svoje potomce,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript obliko: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/sq.csv b/frappe/translations/sq.csv
index cf2c1a5f4e..dd314df2c6 100644
--- a/frappe/translations/sq.csv
+++ b/frappe/translations/sq.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Është Submittable,
Is Table,A Tabela,
Is Your Company Address,Është kompania juaj Adresa,
It is risky to delete this file: {0}. Please contact your System Manager.,Kjo është e rrezikshme për të fshirë këtë skedë: {0}. Ju lutemi të kontaktoni Sistemit Soccer tuaj.,
-Item cannot be added to its own descendents,Item nuk mund të shtohet për të pasardhësve të vet,
+Item cannot be added to its own descendants,Item nuk mund të shtohet për të pasardhësve të vet,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Formati: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/sr.csv b/frappe/translations/sr.csv
index 59f41cedb7..5a607d2a81 100644
--- a/frappe/translations/sr.csv
+++ b/frappe/translations/sr.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Да ли Субмиттабле,
Is Table,је Табела,
Is Your Company Address,Ис Иоур Адреса фирме,
It is risky to delete this file: {0}. Please contact your System Manager.,То је ризично да избришете ову датотеку: {0}. Обратите се свом Систем Манагер.,
-Item cannot be added to its own descendents,Продукт не может быть добавлен в своих собственных потомков,
+Item cannot be added to its own descendants,Продукт не может быть добавлен в своих собственных потомков,
JS,ЈС,
JSON,ЈСОН,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Јава формат : вн.куери_репортс [ ' РЕПОРТНАМЕ ' ] = { },
diff --git a/frappe/translations/sv.csv b/frappe/translations/sv.csv
index 5c6a4fc20f..be38d7fef5 100644
--- a/frappe/translations/sv.csv
+++ b/frappe/translations/sv.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Är Skickad,
Is Table,är Table,
Is Your Company Address,Är ditt Företag Adress,
It is risky to delete this file: {0}. Please contact your System Manager.,Det är riskabelt att ta bort denna fil: {0}. Kontakta din systemadministratören.,
-Item cannot be added to its own descendents,Produkt kan inte läggas till sina egna underprodukter,
+Item cannot be added to its own descendants,Produkt kan inte läggas till sina egna underprodukter,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports ['rapportnamn'] = {},
diff --git a/frappe/translations/sw.csv b/frappe/translations/sw.csv
index 21d0e364d3..82da08bee9 100644
--- a/frappe/translations/sw.csv
+++ b/frappe/translations/sw.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Inawasilishwa,
Is Table,"Je, ni Jedwali",
Is Your Company Address,Ni Anwani ya Kampuni Yako,
It is risky to delete this file: {0}. Please contact your System Manager.,Ni hatari kufuta faili hii: {0}. Tafadhali wasiliana na Meneja wa Mfumo wako.,
-Item cannot be added to its own descendents,Kipengee hawezi kuongezwa kwa wazazi wake,
+Item cannot be added to its own descendants,Kipengee hawezi kuongezwa kwa wazazi wake,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Jarida la Javascript: vivutio vya usafiri ['REPORTNAME'] = {},
diff --git a/frappe/translations/ta.csv b/frappe/translations/ta.csv
index faf857b714..75690e2769 100644
--- a/frappe/translations/ta.csv
+++ b/frappe/translations/ta.csv
@@ -1395,7 +1395,7 @@ Is Submittable,சமர்ப்பிக்க,
Is Table,அட்டவணை உள்ளது,
Is Your Company Address,உங்கள் நிறுவனத்தின் முகவரி,
It is risky to delete this file: {0}. Please contact your System Manager.,இந்த கோப்பு நீக்க ஆபத்தானது: {0}. உங்கள் கணினி மேலாளரைத் தொடர்பு கொள்ளவும்.,
-Item cannot be added to its own descendents,பொருள் அதன் சொந்த ஆதரவாளர்வரை சேர்க்க முடியாது,
+Item cannot be added to its own descendants,பொருள் அதன் சொந்த ஆதரவாளர்வரை சேர்க்க முடியாது,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},ஜாவா வடிவம்: frappe.query_reports [' REPORTNAME '] = { },
diff --git a/frappe/translations/te.csv b/frappe/translations/te.csv
index df72e7e710..4ea5b55143 100644
--- a/frappe/translations/te.csv
+++ b/frappe/translations/te.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable ఉంది,
Is Table,పట్టిక,
Is Your Company Address,మీ కంపెనీ అడ్రస్ ఇస్,
It is risky to delete this file: {0}. Please contact your System Manager.,ఇది ఈ ఫైల్ను మీరు తొలగించాలని ప్రమాదకర ఉంది: {0}. మీ సిస్టమ్ నిర్వాహకుడిని సంప్రదించండి.,
-Item cannot be added to its own descendents,అంశం దాని సొంత వంశస్థులు జోడించబడింది సాధ్యం కాదు,
+Item cannot be added to its own descendants,అంశం దాని సొంత వంశస్థులు జోడించబడింది సాధ్యం కాదు,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},జావాస్క్రిప్ట్ ఫార్మాట్: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/th.csv b/frappe/translations/th.csv
index f168e5ac00..452ef0e961 100644
--- a/frappe/translations/th.csv
+++ b/frappe/translations/th.csv
@@ -1395,7 +1395,7 @@ Is Submittable,เป็น Submittable,
Is Table,เป็นตาราง,
Is Your Company Address,คือที่อยู่ บริษัท ของคุณ,
It is risky to delete this file: {0}. Please contact your System Manager.,มันเป็นความเสี่ยงที่จะลบไฟล์นี้: {0} โปรดติดต่อผู้จัดการของระบบ,
-Item cannot be added to its own descendents,รายการที่ ไม่สามารถเพิ่ม ไปยัง ลูกหลาน ของตัวเอง,
+Item cannot be added to its own descendants,รายการที่ ไม่สามารถเพิ่ม ไปยัง ลูกหลาน ของตัวเอง,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},รูปแบบ JavaScript : frappe.query_reports [ 'ชื่อรายงาน' ] = { },
diff --git a/frappe/translations/tr.csv b/frappe/translations/tr.csv
index a16e68f640..11d7c03535 100644
--- a/frappe/translations/tr.csv
+++ b/frappe/translations/tr.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable mi,
Is Table,Tablo mu,
Is Your Company Address,Firmanız Adresi,
It is risky to delete this file: {0}. Please contact your System Manager.,Bu dosyayı silmek için riskli: {0}. Sistem Yöneticisi irtibata geçiniz.,
-Item cannot be added to its own descendents,"Ürün, kendi soyundan ilave edilemez",
+Item cannot be added to its own descendants,"Ürün, kendi soyundan ilave edilemez",
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Format: frappe.query_reports ['ReportName'] = {},
diff --git a/frappe/translations/uk.csv b/frappe/translations/uk.csv
index bdc06f4b1a..3caa7e6608 100644
--- a/frappe/translations/uk.csv
+++ b/frappe/translations/uk.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Є Submittable,
Is Table,Чи є таблиця,
Is Your Company Address,Є адресою Вашої компанії,
It is risky to delete this file: {0}. Please contact your System Manager.,"Це ризиковано, щоб видалити цей файл: {0}. Будь ласка, зверніться до менеджера системи.",
-Item cannot be added to its own descendents,Товар не може бути доданий у власних нащадків,
+Item cannot be added to its own descendants,Товар не може бути доданий у власних нащадків,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript Формат: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/ur.csv b/frappe/translations/ur.csv
index 21101a7975..639833fa3b 100644
--- a/frappe/translations/ur.csv
+++ b/frappe/translations/ur.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable ہے,
Is Table,ٹیبل ہے,
Is Your Company Address,آپ کی کمپنی ایڈریس ہے,
It is risky to delete this file: {0}. Please contact your System Manager.,اس فائل کو حذف کرنا خطرناک ہے: {0}. آپ کے سسٹم مینیجر سے رابطہ کریں.,
-Item cannot be added to its own descendents,آئٹم کو اس کی اپنی اولاد میں شامل نہیں کیا جا سکتا,
+Item cannot be added to its own descendants,آئٹم کو اس کی اپنی اولاد میں شامل نہیں کیا جا سکتا,
JS,جے ایس,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},جاوا کی شکل: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/uz.csv b/frappe/translations/uz.csv
index 8c1056286b..a94c5ac9b8 100644
--- a/frappe/translations/uz.csv
+++ b/frappe/translations/uz.csv
@@ -1395,7 +1395,7 @@ Is Submittable,Submittable mavjud,
Is Table,Jadval bormi?,
Is Your Company Address,Sizning kompaniyangiz manzili,
It is risky to delete this file: {0}. Please contact your System Manager.,"Ushbu faylni o'chirish xavfli: {0}. Iltimos, tizim boshqaruvchisiga murojaat qiling.",
-Item cannot be added to its own descendents,Mavzu o'z avlodlariga qo'shilmaydi,
+Item cannot be added to its own descendants,Mavzu o'z avlodlariga qo'shilmaydi,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript formati: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/vi.csv b/frappe/translations/vi.csv
index a3e92fd3df..64d27bd96d 100644
--- a/frappe/translations/vi.csv
+++ b/frappe/translations/vi.csv
@@ -1395,7 +1395,7 @@ Is Submittable,CÓ thể đệ trình,
Is Table,là Bảng,
Is Your Company Address,Là Địa chỉ công ty của bạn,
It is risky to delete this file: {0}. Please contact your System Manager.,Có rủi ro khi xóa tập tin này: {0}. Vui lòng liên hệ Quản lý Hệ thống của bạn.,
-Item cannot be added to its own descendents,Mẫu hàng không thể được thêm vào các phần sau của mình,
+Item cannot be added to its own descendants,Mẫu hàng không thể được thêm vào các phần sau của mình,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Định dạng JavaScript: frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/translations/zh-TW.csv b/frappe/translations/zh-TW.csv
index b95eda8b01..3531daa4c0 100644
--- a/frappe/translations/zh-TW.csv
+++ b/frappe/translations/zh-TW.csv
@@ -1765,7 +1765,7 @@ apps/frappe/frappe/public/js/frappe/form/linked_with.js +104,Not enough permissi
apps/frappe/frappe/contacts/doctype/address/address.py +37,Address Title is mandatory.,地址標題是強制性的。
DocType: Website Settings,"Added HTML in the <head> section of the web page, primarily used for website verification and SEO",在<head>添加HTML網頁的部分,主要用於網站的驗證和搜索引擎優化
apps/frappe/frappe/core/doctype/error_snapshot/error_snapshot_list.js +9,Relapsed,復發
-apps/frappe/frappe/utils/nestedset.py +183,Item cannot be added to its own descendents,項目不能被添加到自己的後代
+apps/frappe/frappe/utils/nestedset.py +183,Item cannot be added to its own descendants,項目不能被添加到自己的後代
DocType: System Settings,Expiry time of QR Code Image Page,QR碼圖像頁面的到期時間
apps/frappe/frappe/public/js/frappe/views/reports/reportview.js +614,Show Totals,顯示總計
DocType: Error Snapshot,Relapses,復發
diff --git a/frappe/translations/zh.csv b/frappe/translations/zh.csv
index c82c64b5f5..6f3b3b597f 100644
--- a/frappe/translations/zh.csv
+++ b/frappe/translations/zh.csv
@@ -1395,7 +1395,7 @@ Is Submittable,是否可以提交,
Is Table,为表,
Is Your Company Address,是你的公司地址,
It is risky to delete this file: {0}. Please contact your System Manager.,删除这个文件是有风险的:{0}。请联系您的系统管理员。,
-Item cannot be added to its own descendents,项目不能被添加到自己的后代,
+Item cannot be added to its own descendants,项目不能被添加到自己的后代,
JS,JS,
JSON,JSON,
JavaScript Format: frappe.query_reports['REPORTNAME'] = {},JavaScript格式:frappe.query_reports ['REPORTNAME'] = {},
diff --git a/frappe/utils/file_lock.py b/frappe/utils/file_lock.py
index fc399f7c96..5be89c42f6 100644
--- a/frappe/utils/file_lock.py
+++ b/frappe/utils/file_lock.py
@@ -1,22 +1,34 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
-"""
-File based locking utility
+"""Utils for inter-process synchronization using file-locks.
+
+This file implements a "weak" form lock which is not suitable for synchroniztion. This is only used
+for document locking for queue_action.
+Use `frappe.utils.synchroniztion.filelock` for process synchroniztion.
"""
import os
from time import time
+from frappe import _
from frappe.utils import get_site_path, touch_file
+LOCKS_DIR = "locks"
+
class LockTimeoutError(Exception):
pass
def create_lock(name):
- """Creates a file in the /locks folder by the given name"""
+ """Creates a file in the /locks folder by the given name.
+
+ Note: This is a "weak lock" and is prone to race conditions. Do not use this lock for small
+ sections of code that execute immediately.
+
+ This is primarily use for locking documents for background submission.
+ """
lock_path = get_lock_path(name)
if not check_lock(lock_path):
return touch_file(lock_path)
@@ -48,6 +60,5 @@ def delete_lock(name):
def get_lock_path(name):
name = name.lower()
- locks_dir = "locks"
- lock_path = get_site_path(locks_dir, name + ".lock")
+ lock_path = get_site_path(LOCKS_DIR, name + ".lock")
return lock_path
diff --git a/frappe/utils/install.py b/frappe/utils/install.py
index 1f1f648503..cd15c957f9 100644
--- a/frappe/utils/install.py
+++ b/frappe/utils/install.py
@@ -3,6 +3,7 @@
import getpass
import frappe
+from frappe.geo.doctype.country.country import import_country_and_currency
from frappe.utils.password import update_password
@@ -22,13 +23,10 @@ def after_install():
install_basic_docs()
from frappe.core.doctype.file.utils import make_home_folder
-
- make_home_folder()
-
- import_country_and_currency()
-
from frappe.core.doctype.language.language import sync_languages
+ make_home_folder()
+ import_country_and_currency()
sync_languages()
# save default print setting
@@ -171,6 +169,7 @@ def before_tests():
if not int(frappe.db.get_single_value("System Settings", "setup_complete") or 0):
complete_setup_wizard()
+ frappe.db.set_value("Website Settings", "Website Settings", "disable_signup", 0)
frappe.db.commit()
frappe.clear_cache()
@@ -191,53 +190,6 @@ def complete_setup_wizard():
)
-def import_country_and_currency():
- from frappe.geo.country_info import get_all
- from frappe.utils import update_progress_bar
-
- data = get_all()
-
- for i, name in enumerate(data):
- update_progress_bar("Updating country info", i, len(data))
- country = frappe._dict(data[name])
- add_country_and_currency(name, country)
-
- print("")
-
- # enable frequently used currencies
- for currency in ("INR", "USD", "GBP", "EUR", "AED", "AUD", "JPY", "CNY", "CHF"):
- frappe.db.set_value("Currency", currency, "enabled", 1)
-
-
-def add_country_and_currency(name, country):
- if not frappe.db.exists("Country", name):
- frappe.get_doc(
- {
- "doctype": "Country",
- "country_name": name,
- "code": country.code,
- "date_format": country.date_format or "dd-mm-yyyy",
- "time_format": country.time_format or "HH:mm:ss",
- "time_zones": "\n".join(country.timezones or []),
- "docstatus": 0,
- }
- ).db_insert()
-
- if country.currency and not frappe.db.exists("Currency", country.currency):
- frappe.get_doc(
- {
- "doctype": "Currency",
- "currency_name": country.currency,
- "fraction": country.currency_fraction,
- "symbol": country.currency_symbol,
- "fraction_units": country.currency_fraction_units,
- "smallest_currency_fraction_value": country.smallest_currency_fraction_value,
- "number_format": country.number_format,
- "docstatus": 0,
- }
- ).db_insert()
-
-
def add_standard_navbar_items():
navbar_settings = frappe.get_single("Navbar Settings")
diff --git a/frappe/utils/nestedset.py b/frappe/utils/nestedset.py
index 1112b593c5..374851e019 100644
--- a/frappe/utils/nestedset.py
+++ b/frappe/utils/nestedset.py
@@ -234,7 +234,7 @@ def validate_loop(doctype, name, lft, rgt):
if name in frappe.get_all(
doctype, filters={"lft": ["<=", lft], "rgt": [">=", rgt]}, pluck="name"
):
- frappe.throw(_("Item cannot be added to its own descendents"), NestedSetRecursionError)
+ frappe.throw(_("Item cannot be added to its own descendants"), NestedSetRecursionError)
def remove_subtree(doctype: str, name: str, throw=True):
diff --git a/frappe/utils/synchronization.py b/frappe/utils/synchronization.py
new file mode 100644
index 0000000000..841fab85ff
--- /dev/null
+++ b/frappe/utils/synchronization.py
@@ -0,0 +1,49 @@
+""" Utils for thread/process synchronization. """
+
+import os
+from contextlib import contextmanager
+
+from filelock import FileLock as _StrongFileLock
+from filelock import Timeout
+
+import frappe
+from frappe import _
+from frappe.utils import get_bench_path, get_site_path
+from frappe.utils.file_lock import LockTimeoutError
+
+LOCKS_DIR = "locks"
+
+
+@contextmanager
+def filelock(lock_name: str, *, timeout=30, is_global=False):
+ """Create a lockfile to prevent concurrent operations acrosss processes.
+
+ args:
+ lock_name: Unique name to identify a specific lock. Lockfile called `{name}.lock` will be
+ created.
+ timeout: time to wait before failing.
+ is_global: if set lock is global to bench
+
+ Lock file location:
+ global - {bench_dir}/config/{name}.lock
+ site - {bench_dir}/sites/sitename/{name}.lock
+
+ """
+
+ lock_filename = lock_name + ".lock"
+ if not is_global:
+ lock_path = os.path.abspath(get_site_path(LOCKS_DIR, lock_filename))
+ else:
+ lock_path = os.path.abspath(os.path.join(get_bench_path(), "config", lock_filename))
+
+ try:
+ with _StrongFileLock(lock_path, timeout=timeout):
+ yield
+ except Timeout as e:
+ frappe.log_error("Filelock: Failed to aquire {lock_path}")
+
+ raise LockTimeoutError(
+ _("Failed to aquire lock: {}").format(lock_name)
+ + "
"
+ + _("You can manually remove the lock if you think it's safe: {}").format(lock_path)
+ ) from e
diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py
index d102ac2fd8..73b2dc2331 100644
--- a/frappe/website/doctype/web_form/web_form.py
+++ b/frappe/website/doctype/web_form/web_form.py
@@ -342,7 +342,7 @@ def get_context(context):
return False
if self.apply_document_permissions:
- return frappe.get_doc(doctype, name).has_permission()
+ return frappe.get_doc(doctype, name).has_permission(permtype=ptype)
# owner matches
elif frappe.db.get_value(doctype, name, "owner") == frappe.session.user:
@@ -365,7 +365,7 @@ def get_web_form_module(doc):
@frappe.whitelist(allow_guest=True)
@rate_limit(key="web_form", limit=5, seconds=60, methods=["POST"])
-def accept(web_form, data, docname=None):
+def accept(web_form, data):
"""Save the web form"""
data = frappe._dict(json.loads(data))
@@ -373,19 +373,20 @@ def accept(web_form, data, docname=None):
files_to_delete = []
web_form = frappe.get_doc("Web Form", web_form)
+ doctype = web_form.doc_type
if data.name and not web_form.allow_edit:
frappe.throw(_("You are not allowed to update this Web Form Document"))
frappe.flags.in_web_form = True
- meta = frappe.get_meta(data.doctype)
+ meta = frappe.get_meta(doctype)
- if docname:
+ if data.name:
# update
- doc = frappe.get_doc(data.doctype, docname)
+ doc = frappe.get_doc(doctype, data.name)
else:
# insert
- doc = frappe.new_doc(data.doctype)
+ doc = frappe.new_doc(doctype)
# set values
for field in web_form.web_form_fields:
@@ -406,7 +407,7 @@ def accept(web_form, data, docname=None):
doc.set(fieldname, value)
if doc.name:
- if web_form.has_web_form_permission(doc.doctype, doc.name, "write"):
+ if web_form.has_web_form_permission(doctype, doc.name, "write"):
doc.save(ignore_permissions=True)
else:
# only if permissions are present
@@ -428,7 +429,7 @@ def accept(web_form, data, docname=None):
# remove earlier attached file (if exists)
if doc.get(fieldname):
- remove_file_by_url(doc.get(fieldname), doctype=doc.doctype, name=doc.name)
+ remove_file_by_url(doc.get(fieldname), doctype=doctype, name=doc.name)
# save new file
filename, dataurl = filedata.split(",", 1)
@@ -436,7 +437,7 @@ def accept(web_form, data, docname=None):
{
"doctype": "File",
"file_name": filename,
- "attached_to_doctype": doc.doctype,
+ "attached_to_doctype": doctype,
"attached_to_name": doc.name,
"content": dataurl,
"decode": True,
@@ -452,7 +453,7 @@ def accept(web_form, data, docname=None):
if files_to_delete:
for f in files_to_delete:
if f:
- remove_file_by_url(f, doctype=doc.doctype, name=doc.name)
+ remove_file_by_url(f, doctype=doctype, name=doc.name)
frappe.flags.web_form_doc = doc
return doc
diff --git a/frappe/website/doctype/website_settings/website_settings.json b/frappe/website/doctype/website_settings/website_settings.json
index 29827afd80..3bf7e4cb30 100644
--- a/frappe/website/doctype/website_settings/website_settings.json
+++ b/frappe/website/doctype/website_settings/website_settings.json
@@ -247,7 +247,7 @@
"read_only": 1
},
{
- "default": "0",
+ "default": "1",
"description": "Disable Customer Signup link in Login page",
"fieldname": "disable_signup",
"fieldtype": "Check",
@@ -476,7 +476,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2022-10-18 09:50:24.621839",
+ "modified": "2022-12-05 04:17:56.478757",
"modified_by": "Administrator",
"module": "Website",
"name": "Website Settings",
diff --git a/pyproject.toml b/pyproject.toml
index f5ab8c94b2..dcd7599e9a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,6 +11,7 @@ dependencies = [
# core dependencies
"Babel~=2.9.0",
"Click~=7.1.2",
+ "filelock~=3.8.0",
"GitPython~=3.1.14",
"Jinja2~=3.1.2",
"Pillow~=9.3.0",
diff --git a/yarn.lock b/yarn.lock
index a4204b0c64..acf5e0c9c0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -89,14 +89,16 @@
integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
"@types/cors@^2.8.12":
- version "2.8.12"
- resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080"
- integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==
+ version "2.8.13"
+ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94"
+ integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==
+ dependencies:
+ "@types/node" "*"
-"@types/node@>=10.0.0":
- version "18.0.0"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a"
- integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==
+"@types/node@*", "@types/node@>=10.0.0":
+ version "18.11.11"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.11.tgz#1d455ac0211549a8409d3cdb371cd55cc971e8dc"
+ integrity sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==
"@types/web-bluetooth@^0.0.16":
version "0.0.16"
@@ -316,12 +318,12 @@ abbrev@1:
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
accepts@~1.3.4:
- version "1.3.7"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
- integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
dependencies:
- mime-types "~2.1.24"
- negotiator "0.6.2"
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
ace-builds@^1.4.8:
version "1.4.8"
@@ -726,15 +728,10 @@ constantinople@^4.0.1:
"@babel/parser" "^7.6.0"
"@babel/types" "^7.6.1"
-cookie@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
- integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
-
-cookie@~0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
- integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
+cookie@^0.4.0, cookie@~0.4.1:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
+ integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
cookiejar@^2.1.0:
version "2.1.2"
@@ -1070,9 +1067,9 @@ engine.io-parser@~5.0.3:
integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==
engine.io@~6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.0.tgz#003bec48f6815926f2b1b17873e576acd54f41d0"
- integrity sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.1.tgz#e3f7826ebc4140db9bbaa9021ad6b1efb175878f"
+ integrity sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==
dependencies:
"@types/cookie" "^0.4.1"
"@types/cors" "^2.8.12"
@@ -2104,16 +2101,16 @@ micromatch@^4.0.2:
braces "^3.0.1"
picomatch "^2.0.5"
-mime-db@1.43.0:
- version "1.43.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
- integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
-
mime-db@1.44.0:
version "1.44.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
mime-types@^2.1.12:
version "2.1.27"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
@@ -2121,12 +2118,12 @@ mime-types@^2.1.12:
dependencies:
mime-db "1.44.0"
-mime-types@~2.1.24:
- version "2.1.26"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
- integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
+mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
- mime-db "1.43.0"
+ mime-db "1.52.0"
mime@^1.4.1:
version "1.6.0"
@@ -2201,10 +2198,10 @@ needle@^2.5.2:
iconv-lite "^0.4.4"
sax "^1.2.4"
-negotiator@0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
- integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
node-releases@^1.1.71:
version "1.1.77"
@@ -3551,7 +3548,7 @@ util-deprecate@^1.0.2, util-deprecate@~1.0.1:
vary@^1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
- integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
void-elements@^3.1.0:
version "3.1.0"