Merge branch 'develop' into qb-fixes
This commit is contained in:
commit
862d7428a6
19 changed files with 142 additions and 117 deletions
2
.github/workflows/on_release.yml
vendored
2
.github/workflows/on_release.yml
vendored
|
|
@ -41,7 +41,7 @@ jobs:
|
|||
|
||||
- name: Get release
|
||||
id: get_release
|
||||
uses: bruceadams/get-release@v1.2.3
|
||||
uses: bruceadams/get-release@v1.3.1
|
||||
|
||||
- name: Upload built Assets to Release
|
||||
uses: actions/upload-release-asset@v1.0.2
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ def _(msg: str, lang: str | None = None, context: str | None = None) -> str:
|
|||
_('Change')
|
||||
_('Change', context='Coins')
|
||||
"""
|
||||
from frappe.translate import get_full_dict
|
||||
from frappe.translate import get_all_translations
|
||||
from frappe.utils import is_html, strip_html_tags
|
||||
|
||||
if not hasattr(local, "lang"):
|
||||
|
|
@ -107,14 +107,15 @@ def _(msg: str, lang: str | None = None, context: str | None = None) -> str:
|
|||
msg = as_unicode(msg).strip()
|
||||
|
||||
translated_string = ""
|
||||
|
||||
all_translations = get_all_translations(lang)
|
||||
if context:
|
||||
string_key = f"{msg}:{context}"
|
||||
translated_string = get_full_dict(lang).get(string_key)
|
||||
translated_string = all_translations.get(string_key)
|
||||
|
||||
if not translated_string:
|
||||
translated_string = get_full_dict(lang).get(msg)
|
||||
translated_string = all_translations.get(msg)
|
||||
|
||||
# return lang_full_dict according to lang passed parameter
|
||||
return translated_string or non_translated_string
|
||||
|
||||
|
||||
|
|
@ -222,7 +223,6 @@ def init(site: str, sites_path: str = ".", new_site: bool = False) -> None:
|
|||
|
||||
local.conf = _dict(get_site_config())
|
||||
local.lang = local.conf.lang or "en"
|
||||
local.lang_full_dict = None
|
||||
|
||||
local.module_app = None
|
||||
local.app_modules = None
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import frappe
|
||||
from frappe import _
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
from frappe.translate import clear_cache
|
||||
|
||||
|
||||
class TestTranslation(FrappeTestCase):
|
||||
|
|
@ -11,20 +12,17 @@ class TestTranslation(FrappeTestCase):
|
|||
|
||||
def tearDown(self):
|
||||
frappe.local.lang = "en"
|
||||
clear_translation_cache()
|
||||
clear_cache()
|
||||
|
||||
def test_doctype(self):
|
||||
translation_data = get_translation_data()
|
||||
for key, val in translation_data.items():
|
||||
frappe.local.lang = key
|
||||
|
||||
clear_translation_cache()
|
||||
translation = create_translation(key, val)
|
||||
self.assertEqual(_(val[0]), val[1])
|
||||
|
||||
frappe.delete_doc("Translation", translation.name)
|
||||
clear_translation_cache()
|
||||
|
||||
self.assertEqual(_(val[0]), val[0])
|
||||
|
||||
def test_parent_language(self):
|
||||
|
|
@ -55,6 +53,10 @@ class TestTranslation(FrappeTestCase):
|
|||
clear_translation_cache()
|
||||
self.assertTrue(_(data[1][0]), data[1][1])
|
||||
|
||||
def test_multi_language_translations(self):
|
||||
source = "User"
|
||||
self.assertNotEqual(_(source, lang="de"), _(source, lang="es"))
|
||||
|
||||
def test_html_content_data_translation(self):
|
||||
source = """
|
||||
<span style="color: rgb(51, 51, 51); font-family: "Amazon Ember", Arial, sans-serif; font-size:
|
||||
|
|
@ -113,5 +115,4 @@ def create_translation(key, val):
|
|||
|
||||
|
||||
def clear_translation_cache():
|
||||
frappe.local.lang_full_dict = None
|
||||
frappe.cache().delete_key("lang_full_dict", shared=True)
|
||||
frappe.cache().delete_key("translations_from_apps", shared=True)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import json
|
|||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.translate import get_translator_url
|
||||
from frappe.translate import MERGED_TRANSLATION_KEY, USER_TRANSLATION_KEY, get_translator_url
|
||||
from frappe.utils import is_html, strip_html_tags
|
||||
|
||||
|
||||
|
|
@ -89,4 +89,5 @@ def create_translations(translation_map, language):
|
|||
|
||||
|
||||
def clear_user_translation_cache(lang):
|
||||
frappe.cache().hdel("lang_user_translations", lang)
|
||||
frappe.cache().hdel(USER_TRANSLATION_KEY, lang)
|
||||
frappe.cache().hdel(MERGED_TRANSLATION_KEY, lang)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,16 @@ frappe.ui.form.on("User", {
|
|||
}
|
||||
},
|
||||
|
||||
time_zone: function (frm) {
|
||||
if (frm.doc.time_zone && frm.doc.time_zone.startsWith("Etc")) {
|
||||
frm.set_df_property(
|
||||
"time_zone",
|
||||
"description",
|
||||
__("Note: Etc timezones have their signs reversed.")
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
role_profile_name: function (frm) {
|
||||
if (frm.doc.role_profile_name) {
|
||||
frappe.call({
|
||||
|
|
@ -259,6 +269,7 @@ frappe.ui.form.on("User", {
|
|||
}
|
||||
frm.dirty();
|
||||
}
|
||||
frm.trigger("time_zone");
|
||||
},
|
||||
validate: function (frm) {
|
||||
if (frm.roles_editor) {
|
||||
|
|
|
|||
|
|
@ -17,15 +17,16 @@ expected_settings_10_3_later = {
|
|||
}
|
||||
|
||||
|
||||
def get_mariadb_versions():
|
||||
def get_mariadb_variables():
|
||||
return frappe._dict(frappe.db.sql("show variables"))
|
||||
|
||||
|
||||
def get_mariadb_version(version_string: str = ""):
|
||||
# MariaDB classifies their versions as Major (1st and 2nd number), and Minor (3rd number)
|
||||
# Example: Version 10.3.13 is Major Version = 10.3, Minor Version = 13
|
||||
mariadb_variables = frappe._dict(frappe.db.sql("""show variables"""))
|
||||
version_string = mariadb_variables.get("version").split("-")[0]
|
||||
versions = {}
|
||||
versions["major"] = version_string.split(".")[0] + "." + version_string.split(".")[1]
|
||||
versions["minor"] = version_string.split(".")[2]
|
||||
return versions
|
||||
version_string = version_string or get_mariadb_variables().get("version")
|
||||
version = version_string.split("-")[0]
|
||||
return version.rsplit(".", 1)
|
||||
|
||||
|
||||
def setup_database(force, source_sql, verbose, no_mariadb_socket=False):
|
||||
|
|
@ -108,13 +109,13 @@ def import_db_from_sql(source_sql=None, verbose=False):
|
|||
|
||||
|
||||
def check_database_settings():
|
||||
versions = get_mariadb_versions()
|
||||
if versions["major"] <= "10.2":
|
||||
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
|
||||
|
||||
mariadb_variables = frappe._dict(frappe.db.sql("show variables"))
|
||||
# Check each expected value vs. actuals:
|
||||
result = True
|
||||
for key, expected_value in expected_variables.items():
|
||||
|
|
@ -124,18 +125,16 @@ def check_database_settings():
|
|||
% (key, expected_value, mariadb_variables.get(key))
|
||||
)
|
||||
result = False
|
||||
|
||||
if not result:
|
||||
print(
|
||||
(
|
||||
"=" * 80 + "\n"
|
||||
"Creation of your site - {x} failed because MariaDB is not properly {sep}"
|
||||
"{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. {sep}{sep}"
|
||||
"Please verify the settings above in MariaDB's my.cnf. Restart MariaDB. And {sep}"
|
||||
"then run `bench new-site {x}` again.{sep2}"
|
||||
""
|
||||
"=" * 80
|
||||
).format(x=frappe.local.site, sep2="\n" * 2, sep="\n")
|
||||
"the Barracuda storage engine.{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")
|
||||
)
|
||||
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ frappe.listview_settings["ToDo"] = {
|
|||
return doc.reference_name;
|
||||
},
|
||||
get_label: function () {
|
||||
return __("Open");
|
||||
return __("Open", null, "Access");
|
||||
},
|
||||
get_description: function (doc) {
|
||||
return __("Open {0}", [`${doc.reference_type} ${doc.reference_name}`]);
|
||||
return __("Open {0}", [`${__(doc.reference_type)}: ${doc.reference_name}`]);
|
||||
},
|
||||
action: function (doc) {
|
||||
frappe.set_route("Form", doc.reference_type, doc.reference_name);
|
||||
|
|
|
|||
|
|
@ -604,6 +604,9 @@ class Email:
|
|||
fname = get_random_filename(content_type=content_type)
|
||||
else:
|
||||
fname = get_random_filename(content_type=content_type)
|
||||
# Don't clobber existing filename
|
||||
while fname in self.cid_map:
|
||||
fname = get_random_filename(content_type=content_type)
|
||||
|
||||
self.attachments.append(
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import { useRoute } from "vue-router"
|
|||
|
||||
let route = useRoute();
|
||||
|
||||
watch(route, () => {
|
||||
frappe.router.current_route = frappe.router.parse();
|
||||
watch(route, async () => {
|
||||
frappe.router.current_route = await frappe.router.parse();
|
||||
frappe.breadcrumbs.update();
|
||||
frappe.recorder.route = route;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,16 +38,17 @@ $("body").on("click", "a", function (e) {
|
|||
return false;
|
||||
};
|
||||
|
||||
const href = e.currentTarget.getAttribute("href");
|
||||
const target_element = e.currentTarget;
|
||||
const href = target_element.getAttribute("href");
|
||||
const is_on_same_host = target_element.hostname === window.location.hostname;
|
||||
|
||||
// click handled, but not by href
|
||||
if (
|
||||
e.currentTarget.getAttribute("onclick") || // has a handler
|
||||
target_element.getAttribute("onclick") || // has a handler
|
||||
e.ctrlKey ||
|
||||
e.metaKey || // open in a new tab
|
||||
href === "#"
|
||||
href === "#" // hash is home
|
||||
) {
|
||||
// hash is home
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -57,20 +58,20 @@ $("body").on("click", "a", function (e) {
|
|||
|
||||
if (href && href.startsWith("#")) {
|
||||
// target startswith "#", this is a v1 style route, so remake it.
|
||||
return override(e.currentTarget.hash);
|
||||
return override(target_element.hash);
|
||||
}
|
||||
|
||||
if (frappe.router.is_app_route(e.currentTarget.pathname)) {
|
||||
if (is_on_same_host && frappe.router.is_app_route(target_element.pathname)) {
|
||||
// target has "/app, this is a v2 style route.
|
||||
|
||||
if (e.currentTarget.search) {
|
||||
if (target_element.search) {
|
||||
frappe.route_options = {};
|
||||
let params = new URLSearchParams(e.currentTarget.search);
|
||||
let params = new URLSearchParams(target_element.search);
|
||||
for (const [key, value] of params) {
|
||||
frappe.route_options[key] = value;
|
||||
}
|
||||
}
|
||||
return override(e.currentTarget.pathname + e.currentTarget.hash);
|
||||
return override(target_element.pathname + target_element.hash);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -88,6 +89,7 @@ frappe.router = {
|
|||
"dashboard",
|
||||
"image",
|
||||
"inbox",
|
||||
"map",
|
||||
],
|
||||
list_views_route: {
|
||||
list: "List",
|
||||
|
|
@ -100,6 +102,7 @@ frappe.router = {
|
|||
image: "Image",
|
||||
inbox: "Inbox",
|
||||
file: "Home",
|
||||
map: "Map",
|
||||
},
|
||||
layout_mapped: {},
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,6 @@ class TestSearch(FrappeTestCase):
|
|||
def test_link_search_in_foreign_language(self):
|
||||
try:
|
||||
frappe.local.lang = "fr"
|
||||
frappe.local.lang_full_dict = None # discard translation cache
|
||||
search_widget(doctype="DocType", txt="pay", page_length=20)
|
||||
output = frappe.response["values"]
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ def _restore_thread_locals(flags):
|
|||
frappe.local.conf = frappe._dict(frappe.get_site_config())
|
||||
frappe.local.cache = {}
|
||||
frappe.local.lang = "en"
|
||||
frappe.local.lang_full_dict = None
|
||||
frappe.local.preload_assets = {"style": [], "script": []}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,12 @@ REPORT_TRANSLATE_PATTERN = re.compile('"([^:,^"]*):')
|
|||
CSV_STRIP_WHITESPACE_PATTERN = re.compile(r"{\s?([0-9]+)\s?}")
|
||||
|
||||
|
||||
# Cache keys
|
||||
MERGED_TRANSLATION_KEY = "merged_translations"
|
||||
APP_TRANSLATION_KEY = "translations_from_apps"
|
||||
USER_TRANSLATION_KEY = "lang_user_translations"
|
||||
|
||||
|
||||
def get_language(lang_list: list = None) -> str:
|
||||
"""Set `frappe.local.lang` from HTTP headers at beginning of request
|
||||
|
||||
|
|
@ -215,7 +221,7 @@ def get_dict(fortype: str, name: str | None = None) -> dict[str, str]:
|
|||
|
||||
def get_messages_for_boot():
|
||||
"""Return all message translations that are required on boot."""
|
||||
messages = get_full_dict(frappe.local.lang)
|
||||
messages = get_all_translations(frappe.local.lang)
|
||||
messages.update(get_dict_from_hooks("boot", None))
|
||||
|
||||
return messages
|
||||
|
|
@ -241,9 +247,9 @@ def make_dict_from_messages(messages, full_dict=None, load_user_translation=True
|
|||
out = {}
|
||||
if full_dict is None:
|
||||
if load_user_translation:
|
||||
full_dict = get_full_dict(frappe.local.lang)
|
||||
full_dict = get_all_translations(frappe.local.lang)
|
||||
else:
|
||||
full_dict = load_lang(frappe.local.lang)
|
||||
full_dict = get_translations_from_apps(frappe.local.lang)
|
||||
|
||||
for m in messages:
|
||||
if m[1] in full_dict:
|
||||
|
|
@ -266,31 +272,29 @@ def get_lang_js(fortype: str, name: str) -> str:
|
|||
return f"\n\n$.extend(frappe._messages, {json.dumps(get_dict(fortype, name))})"
|
||||
|
||||
|
||||
def get_full_dict(lang: str) -> dict[str, str]:
|
||||
"""Load and return the entire translations dictionary for a language from :meth:`frape.cache`
|
||||
def get_all_translations(lang: str) -> dict[str, str]:
|
||||
"""Load and return the entire translations dictionary for a language from apps + user translations.
|
||||
|
||||
:param lang: Language Code, e.g. `hi`
|
||||
"""
|
||||
if not lang:
|
||||
return {}
|
||||
|
||||
# found in local, return!
|
||||
if getattr(frappe.local, "lang_full_dict", None) is not None:
|
||||
return frappe.local.lang_full_dict
|
||||
def _merge_translations():
|
||||
all_translations = get_translations_from_apps(lang).copy()
|
||||
try:
|
||||
# get user specific translation data
|
||||
user_translations = get_user_translations(lang)
|
||||
all_translations.update(user_translations)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
frappe.local.lang_full_dict = load_lang(lang)
|
||||
return all_translations
|
||||
|
||||
try:
|
||||
# get user specific translation data
|
||||
user_translations = get_user_translations(lang)
|
||||
frappe.local.lang_full_dict.update(user_translations)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return frappe.local.lang_full_dict
|
||||
return frappe.cache().hget(MERGED_TRANSLATION_KEY, lang, generator=_merge_translations)
|
||||
|
||||
|
||||
def load_lang(lang, apps=None):
|
||||
def get_translations_from_apps(lang, apps=None):
|
||||
"""Combine all translations from `.csv` files in all `apps`.
|
||||
For derivative languages (es-GT), take translations from the
|
||||
base language (es) and then update translations from the child (es-GT)"""
|
||||
|
|
@ -298,22 +302,20 @@ def load_lang(lang, apps=None):
|
|||
if lang == "en":
|
||||
return {}
|
||||
|
||||
out = frappe.cache().hget("lang_full_dict", lang, shared=True)
|
||||
if not out:
|
||||
out = {}
|
||||
def _get_from_disk():
|
||||
translations = {}
|
||||
for app in apps or frappe.get_all_apps(True):
|
||||
path = os.path.join(frappe.get_pymodule_path(app), "translations", lang + ".csv")
|
||||
out.update(get_translation_dict_from_file(path, lang, app) or {})
|
||||
|
||||
translations.update(get_translation_dict_from_file(path, lang, app) or {})
|
||||
if "-" in lang:
|
||||
parent = lang.split("-")[0]
|
||||
parent_out = load_lang(parent)
|
||||
parent_out.update(out)
|
||||
out = parent_out
|
||||
parent_translations = get_translations_from_apps(parent)
|
||||
parent_translations.update(translations)
|
||||
return parent_translations
|
||||
|
||||
frappe.cache().hset("lang_full_dict", lang, out, shared=True)
|
||||
return translations
|
||||
|
||||
return out or {}
|
||||
return frappe.cache().hget(APP_TRANSLATION_KEY, lang, shared=True, generator=_get_from_disk)
|
||||
|
||||
|
||||
def get_translation_dict_from_file(path, lang, app, throw=False) -> dict[str, str]:
|
||||
|
|
@ -342,23 +344,22 @@ def get_translation_dict_from_file(path, lang, app, throw=False) -> dict[str, st
|
|||
def get_user_translations(lang):
|
||||
if not frappe.db:
|
||||
frappe.connect()
|
||||
out = frappe.cache().hget("lang_user_translations", lang)
|
||||
if out is None:
|
||||
out = {}
|
||||
user_translations = frappe.get_all(
|
||||
|
||||
def _read_from_db():
|
||||
user_translations = {}
|
||||
translations = frappe.get_all(
|
||||
"Translation", fields=["source_text", "translated_text", "context"], filters={"language": lang}
|
||||
)
|
||||
|
||||
for translation in user_translations:
|
||||
key = translation.source_text
|
||||
value = translation.translated_text
|
||||
if translation.context:
|
||||
key += ":" + translation.context
|
||||
out[key] = value
|
||||
for t in translations:
|
||||
key = t.source_text
|
||||
value = t.translated_text
|
||||
if t.context:
|
||||
key += ":" + t.context
|
||||
user_translations[key] = value
|
||||
return user_translations
|
||||
|
||||
frappe.cache().hset("lang_user_translations", lang, out)
|
||||
|
||||
return out
|
||||
return frappe.cache().hget(USER_TRANSLATION_KEY, lang, generator=_read_from_db)
|
||||
|
||||
|
||||
def clear_cache():
|
||||
|
|
@ -368,9 +369,10 @@ def clear_cache():
|
|||
|
||||
# clear translations saved in boot cache
|
||||
cache.delete_key("bootinfo")
|
||||
cache.delete_key("lang_full_dict", shared=True)
|
||||
cache.delete_key("translation_assets", shared=True)
|
||||
cache.delete_key("lang_user_translations")
|
||||
cache.delete_key(APP_TRANSLATION_KEY, shared=True)
|
||||
cache.delete_key(USER_TRANSLATION_KEY)
|
||||
cache.delete_key(MERGED_TRANSLATION_KEY)
|
||||
|
||||
|
||||
def get_messages_for_app(app, deduplicate=True):
|
||||
|
|
@ -1050,7 +1052,7 @@ def get_untranslated(lang, untranslated_file, get_all=False, app="_ALL_APPS"):
|
|||
# replace \n with ||| so that internal linebreaks don't get split
|
||||
f.write((escape_newlines(m[1]) + os.linesep).encode("utf-8"))
|
||||
else:
|
||||
full_dict = get_full_dict(lang)
|
||||
full_dict = get_all_translations(lang)
|
||||
|
||||
for m in messages:
|
||||
if not full_dict.get(m[1]):
|
||||
|
|
@ -1073,7 +1075,7 @@ def update_translations(lang, untranslated_file, translated_file, app="_ALL_APPS
|
|||
:param untranslated_file: File path with the messages in English.
|
||||
:param translated_file: File path with messages in language to be updated."""
|
||||
clear_cache()
|
||||
full_dict = get_full_dict(lang)
|
||||
full_dict = get_all_translations(lang)
|
||||
|
||||
def restore_newlines(s):
|
||||
return (
|
||||
|
|
@ -1110,7 +1112,7 @@ def update_translations(lang, untranslated_file, translated_file, app="_ALL_APPS
|
|||
def import_translations(lang, path):
|
||||
"""Import translations from file in standard format"""
|
||||
clear_cache()
|
||||
full_dict = get_full_dict(lang)
|
||||
full_dict = get_all_translations(lang)
|
||||
full_dict.update(get_translation_dict_from_file(path, lang, "import"))
|
||||
|
||||
for app in frappe.get_all_apps(True):
|
||||
|
|
@ -1140,7 +1142,9 @@ def write_translations_file(app, lang, full_dict=None, app_messages=None):
|
|||
|
||||
tpath = frappe.get_pymodule_path(app, "translations")
|
||||
frappe.create_folder(tpath)
|
||||
write_csv_file(os.path.join(tpath, lang + ".csv"), app_messages, full_dict or get_full_dict(lang))
|
||||
write_csv_file(
|
||||
os.path.join(tpath, lang + ".csv"), app_messages, full_dict or get_all_translations(lang)
|
||||
)
|
||||
|
||||
|
||||
def send_translations(translation_dict):
|
||||
|
|
@ -1302,3 +1306,8 @@ def get_translated_doctypes():
|
|||
"Property Setter", {"property": "translated_doctype", "value": "1"}, pluck="doc_type"
|
||||
)
|
||||
return unique(dts + custom_dts)
|
||||
|
||||
|
||||
# Backward compatibility
|
||||
get_full_dict = get_all_translations
|
||||
load_lang = get_translations_from_apps
|
||||
|
|
|
|||
|
|
@ -2593,6 +2593,7 @@ Tree,Baum,
|
|||
Trigger Method,Trigger-Methode,
|
||||
Trigger Name,Name des Auslösers,
|
||||
"Trigger on valid methods like ""before_insert"", ""after_update"", etc (will depend on the DocType selected)","Trigger auf gültige Methoden wie "before_insert", "after_update" usw. (hängt von der DocType ausgewählt)",
|
||||
Try a naming Series, Nummernkreis testen,
|
||||
Try to avoid repeated words and characters,"Versuchen Sie, wiederholte Wörter und Zeichen zu vermeiden",
|
||||
Try to use a longer keyboard pattern with more turns,"Versuchen Sie, eine längere Tastaturmuster mit mehr Windungen zu verwenden",
|
||||
Two Factor Authentication,Zwei-Faktor-Authentifizierung,
|
||||
|
|
|
|||
|
|
|
@ -98,7 +98,6 @@ def get_context(context):
|
|||
"""Build context to render the `web_form.html` template"""
|
||||
context.in_edit_mode = False
|
||||
context.in_view_mode = False
|
||||
self.set_web_form_module()
|
||||
|
||||
if frappe.form_dict.is_list:
|
||||
context.template = "website/doctype/web_form/templates/web_list.html"
|
||||
|
|
@ -284,13 +283,14 @@ def get_context(context):
|
|||
|
||||
def add_custom_context_and_script(self, context):
|
||||
"""Update context from module if standard and append script"""
|
||||
if self.web_form_module:
|
||||
new_context = self.web_form_module.get_context(context)
|
||||
if self.is_standard:
|
||||
web_form_module = get_web_form_module(self)
|
||||
new_context = web_form_module.get_context(context)
|
||||
|
||||
if new_context:
|
||||
context.update(new_context)
|
||||
|
||||
js_path = os.path.join(os.path.dirname(self.web_form_module.__file__), scrub(self.name) + ".js")
|
||||
js_path = os.path.join(os.path.dirname(web_form_module.__file__), scrub(self.name) + ".js")
|
||||
if os.path.exists(js_path):
|
||||
script = frappe.render_template(open(js_path).read(), context)
|
||||
|
||||
|
|
@ -300,9 +300,7 @@ def get_context(context):
|
|||
|
||||
context.script = script
|
||||
|
||||
css_path = os.path.join(
|
||||
os.path.dirname(self.web_form_module.__file__), scrub(self.name) + ".css"
|
||||
)
|
||||
css_path = os.path.join(os.path.dirname(web_form_module.__file__), scrub(self.name) + ".css")
|
||||
if os.path.exists(css_path):
|
||||
style = open(css_path).read()
|
||||
|
||||
|
|
@ -322,14 +320,6 @@ def get_context(context):
|
|||
|
||||
return parents
|
||||
|
||||
def set_web_form_module(self):
|
||||
"""Get custom web form module if exists"""
|
||||
self.web_form_module = self.get_web_form_module()
|
||||
|
||||
def get_web_form_module(self):
|
||||
if self.is_standard:
|
||||
return get_doc_module(self.module, self.doctype, self.name)
|
||||
|
||||
def validate_mandatory(self, doc):
|
||||
"""Validate mandatory web form fields"""
|
||||
missing = []
|
||||
|
|
@ -368,6 +358,11 @@ def get_context(context):
|
|||
return False
|
||||
|
||||
|
||||
def get_web_form_module(doc):
|
||||
if doc.is_standard:
|
||||
return get_doc_module(doc.module, doc.doctype, doc.name)
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
@rate_limit(key="web_form", limit=5, seconds=60, methods=["POST"])
|
||||
def accept(web_form, data, docname=None):
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ frappe.ui.form.on("Website Theme", {
|
|||
} else {
|
||||
frm.enable_save();
|
||||
}
|
||||
frm.set_df_property("custom_scss", "max_lines", 45);
|
||||
},
|
||||
|
||||
set_default_theme_button_and_indicator(frm) {
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"bootstrap_theme_section",
|
||||
"theme",
|
||||
"module",
|
||||
"custom",
|
||||
"bootstrap_theme_section",
|
||||
"google_font",
|
||||
"font_size",
|
||||
"font_properties",
|
||||
|
|
@ -73,8 +73,8 @@
|
|||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "custom_js_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Custom JS"
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Script"
|
||||
},
|
||||
{
|
||||
"fieldname": "js",
|
||||
|
|
@ -84,7 +84,7 @@
|
|||
},
|
||||
{
|
||||
"fieldname": "bootstrap_theme_section",
|
||||
"fieldtype": "Section Break",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Theme Configuration"
|
||||
},
|
||||
{
|
||||
|
|
@ -123,7 +123,7 @@
|
|||
},
|
||||
{
|
||||
"fieldname": "stylesheet_section",
|
||||
"fieldtype": "Section Break",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Stylesheet"
|
||||
},
|
||||
{
|
||||
|
|
@ -181,10 +181,11 @@
|
|||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-01-18 17:43:39.804765",
|
||||
"modified": "2022-10-25 22:15:53.601571",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Website Theme",
|
||||
"naming_rule": "By fieldname",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
|
|
@ -206,5 +207,6 @@
|
|||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -163,6 +163,7 @@ def prepare_filters(doctype, controller, kwargs):
|
|||
|
||||
def get_list_context(context, doctype, web_form_name=None):
|
||||
from frappe.modules import load_doctype_module
|
||||
from frappe.website.doctype.web_form.web_form import get_web_form_module
|
||||
|
||||
list_context = context or frappe._dict()
|
||||
meta = frappe.get_meta(doctype)
|
||||
|
|
@ -193,7 +194,7 @@ def get_list_context(context, doctype, web_form_name=None):
|
|||
# get context from web form module
|
||||
if web_form_name:
|
||||
web_form = frappe.get_doc("Web Form", web_form_name)
|
||||
list_context = update_context_from_module(web_form.get_web_form_module(), list_context)
|
||||
list_context = update_context_from_module(get_web_form_module(web_form), list_context)
|
||||
|
||||
# get path from '/templates/' folder of the doctype
|
||||
if not meta.custom and not list_context.row_template:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ dependencies = [
|
|||
"Click~=7.1.2",
|
||||
"GitPython~=3.1.14",
|
||||
"Jinja2~=3.1.2",
|
||||
"Pillow~=9.1.1",
|
||||
"Pillow~=9.2.0",
|
||||
"PyJWT~=2.4.0",
|
||||
"PyMySQL~=1.0.2",
|
||||
"PyPDF2~=2.1.0",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue