Merge branch 'develop' into refactor-like-unlike
This commit is contained in:
commit
21780d2d2e
21 changed files with 114 additions and 35 deletions
|
|
@ -186,6 +186,7 @@
|
|||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:!in_list(['Tab Break', 'Table'], doc.fieldtype)",
|
||||
"fieldname": "allow_in_quick_entry",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow in Quick Entry"
|
||||
|
|
@ -581,7 +582,7 @@
|
|||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-02-01 15:55:44.007917",
|
||||
"modified": "2024-03-21 17:35:32.602933",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocField",
|
||||
|
|
@ -591,4 +592,4 @@
|
|||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
"column_break_uhqk",
|
||||
"login_with_email_link",
|
||||
"login_with_email_link_expiry",
|
||||
"rate_limit_email_link_login",
|
||||
"brute_force_security",
|
||||
"allow_consecutive_login_attempts",
|
||||
"column_break_34",
|
||||
|
|
@ -656,12 +657,19 @@
|
|||
"fieldname": "store_attached_pdf_document",
|
||||
"fieldtype": "Check",
|
||||
"label": "Store Attached PDF Document"
|
||||
},
|
||||
{
|
||||
"depends_on": "login_with_email_link",
|
||||
"description": "You can set a high value here if multiple users will be logging in from the same network.",
|
||||
"fieldname": "rate_limit_email_link_login",
|
||||
"fieldtype": "Int",
|
||||
"label": "Rate limit for email link login"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-cog",
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-14 15:18:01.465057",
|
||||
"modified": "2024-03-22 15:43:48.347441",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "System Settings",
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ class SystemSettings(Document):
|
|||
]
|
||||
otp_issuer_name: DF.Data | None
|
||||
password_reset_limit: DF.Int
|
||||
rate_limit_email_link_login: DF.Int
|
||||
reset_password_link_expiry_duration: DF.Duration | None
|
||||
reset_password_template: DF.Link | None
|
||||
rounding_method: DF.Literal["Banker's Rounding (legacy)", "Banker's Rounding", "Commercial Rounding"]
|
||||
|
|
|
|||
|
|
@ -171,7 +171,8 @@ class User(Document):
|
|||
self.validate_username()
|
||||
self.remove_disabled_roles()
|
||||
self.validate_user_email_inbox()
|
||||
ask_pass_update()
|
||||
if self.user_emails:
|
||||
ask_pass_update()
|
||||
self.validate_allowed_modules()
|
||||
self.validate_user_image()
|
||||
self.set_time_zone()
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ def search_widget(
|
|||
formatted_fields = [f"`tab{meta.name}`.`{f.strip()}`" for f in fields]
|
||||
|
||||
# Insert title field query after name
|
||||
if meta.show_title_field_in_link:
|
||||
if meta.show_title_field_in_link and meta.title_field:
|
||||
formatted_fields.insert(1, f"`tab{meta.name}`.{meta.title_field} as `label`")
|
||||
|
||||
order_by_based_on_meta = get_order_by(doctype, meta)
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ def get_context(doc):
|
|||
|
||||
|
||||
def enqueue_webhook(doc, webhook) -> None:
|
||||
request_url = headers = data = None
|
||||
request_url = headers = data = r = None
|
||||
try:
|
||||
webhook: Webhook = frappe.get_doc("Webhook", webhook.get("name"))
|
||||
request_url = webhook.request_url
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgstr ""
|
|||
"Project-Id-Version: frappe\n"
|
||||
"Report-Msgid-Bugs-To: developers@frappe.io\n"
|
||||
"POT-Creation-Date: 2024-03-17 09:33+0000\n"
|
||||
"PO-Revision-Date: 2024-03-20 11:37\n"
|
||||
"PO-Revision-Date: 2024-03-22 11:38\n"
|
||||
"Last-Translator: developers@frappe.io\n"
|
||||
"Language-Team: Spanish\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
|
@ -13910,7 +13910,7 @@ msgstr "Google"
|
|||
#: website/doctype/website_settings/website_settings.json
|
||||
msgctxt "Website Settings"
|
||||
msgid "Google Analytics ID"
|
||||
msgstr ""
|
||||
msgstr "ID de Google Analytics"
|
||||
|
||||
#. Label of a Check field in DocType 'Website Settings'
|
||||
#: website/doctype/website_settings/website_settings.json
|
||||
|
|
@ -15014,19 +15014,19 @@ msgstr ""
|
|||
#. Name of a DocType
|
||||
#: email/doctype/imap_folder/imap_folder.json
|
||||
msgid "IMAP Folder"
|
||||
msgstr ""
|
||||
msgstr "Carpeta IMAP"
|
||||
|
||||
#. Label of a Data field in DocType 'Communication'
|
||||
#: core/doctype/communication/communication.json
|
||||
msgctxt "Communication"
|
||||
msgid "IMAP Folder"
|
||||
msgstr ""
|
||||
msgstr "Carpeta IMAP"
|
||||
|
||||
#. Label of a Table field in DocType 'Email Account'
|
||||
#: email/doctype/email_account/email_account.json
|
||||
msgctxt "Email Account"
|
||||
msgid "IMAP Folder"
|
||||
msgstr ""
|
||||
msgstr "Carpeta IMAP"
|
||||
|
||||
#. Label of a Data field in DocType 'Activity Log'
|
||||
#: core/doctype/activity_log/activity_log.json
|
||||
|
|
@ -15892,7 +15892,7 @@ msgstr "Incluir símbolos, números y letras mayúsculas en la contraseña"
|
|||
#: email/doctype/email_account/email_account.json
|
||||
msgctxt "Email Account"
|
||||
msgid "Incoming (POP/IMAP) Settings"
|
||||
msgstr ""
|
||||
msgstr "Configuración entrante (POP/IMAP)"
|
||||
|
||||
#. Label of a Data field in DocType 'Email Account'
|
||||
#: email/doctype/email_account/email_account.json
|
||||
|
|
@ -28056,7 +28056,7 @@ msgstr "Buscar en un tipo de documento."
|
|||
|
||||
#: public/js/frappe/ui/toolbar/navbar.html:29
|
||||
msgid "Search or type a command ({0})"
|
||||
msgstr ""
|
||||
msgstr "Buscar o escribir un comando ({0})"
|
||||
|
||||
#: templates/includes/search_box.html:8
|
||||
msgid "Search results for"
|
||||
|
|
|
|||
|
|
@ -1089,11 +1089,6 @@ class DatabaseQuery:
|
|||
f"`tab{self.doctype}`.`{sort_field or 'modified'}` {sort_order or 'desc'}"
|
||||
)
|
||||
|
||||
# draft docs always on top
|
||||
if hasattr(self.doctype_meta, "is_submittable") and self.doctype_meta.is_submittable:
|
||||
if self.order_by:
|
||||
args.order_by = f"`tab{self.doctype}`.docstatus asc, {args.order_by}"
|
||||
|
||||
def validate_order_by_and_group_by(self, parameters: str):
|
||||
"""Check order by, group by so that atleast one column is selected and does not have subquery"""
|
||||
if not parameters:
|
||||
|
|
|
|||
|
|
@ -283,6 +283,7 @@ function format_content_for_timeline(content) {
|
|||
// limits content to 40 characters
|
||||
// escapes HTML
|
||||
// and makes it bold
|
||||
content = frappe.utils.html2text(content);
|
||||
content = frappe.ellipsis(content, 40) || '""';
|
||||
content = frappe.utils.escape_html(content);
|
||||
return content.bold();
|
||||
|
|
|
|||
|
|
@ -462,15 +462,22 @@ frappe.views.BaseList = class BaseList {
|
|||
}
|
||||
|
||||
get_args() {
|
||||
let filters = this.get_filters_for_args();
|
||||
let group_by = this.get_group_by();
|
||||
let group_by_required =
|
||||
Array.isArray(filters) &&
|
||||
filters.some((filter) => {
|
||||
return filter[0] !== this.doctype;
|
||||
});
|
||||
return {
|
||||
doctype: this.doctype,
|
||||
fields: this.get_fields(),
|
||||
filters: this.get_filters_for_args(),
|
||||
filters,
|
||||
order_by: this.sort_selector && this.sort_selector.get_sql_string(),
|
||||
start: this.start,
|
||||
page_length: this.page_length,
|
||||
view: this.view,
|
||||
group_by: this.get_group_by(),
|
||||
group_by: group_by_required ? group_by : null,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -740,6 +740,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
${right}
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-row-border"></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ frappe.views.CommunicationComposer = class {
|
|||
fieldtype: "MultiSelect",
|
||||
reqd: 0,
|
||||
fieldname: "recipients",
|
||||
default: this.get_default_recipients("recipients"),
|
||||
},
|
||||
{
|
||||
fieldtype: "Button",
|
||||
|
|
@ -72,11 +73,13 @@ frappe.views.CommunicationComposer = class {
|
|||
label: __("CC"),
|
||||
fieldtype: "MultiSelect",
|
||||
fieldname: "cc",
|
||||
default: this.get_default_recipients("cc"),
|
||||
},
|
||||
{
|
||||
label: __("BCC"),
|
||||
fieldtype: "MultiSelect",
|
||||
fieldname: "bcc",
|
||||
default: this.get_default_recipients("bcc"),
|
||||
},
|
||||
{
|
||||
label: __("Schedule Send At"),
|
||||
|
|
@ -199,6 +202,14 @@ frappe.views.CommunicationComposer = class {
|
|||
return fields;
|
||||
}
|
||||
|
||||
get_default_recipients(fieldname) {
|
||||
if (this.frm?.events.get_email_recipients) {
|
||||
return (this.frm.events.get_email_recipients(this.frm, fieldname) || []).join(", ");
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
guess_language() {
|
||||
// when attach print for print format changes try to guess language
|
||||
// if print format has language then set that else boot lang.
|
||||
|
|
|
|||
|
|
@ -743,6 +743,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
.finally(() => {
|
||||
this.hide_loading_screen();
|
||||
this.update_url_with_filters();
|
||||
this.report_settings.after_refresh?.(this);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1471,7 +1471,8 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
|
|||
if (this.add_totals_row) {
|
||||
const total_data = this.get_columns_totals(this.data);
|
||||
|
||||
total_data["name"] = __("Totals").bold();
|
||||
total_data["name"] = __("Total");
|
||||
total_data.is_total_row = true;
|
||||
rows_in_order.push(total_data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,22 +59,30 @@
|
|||
}
|
||||
|
||||
.list-row-container {
|
||||
border-bottom: 1px solid $border-color;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
outline: none;
|
||||
padding: 4px 5px;
|
||||
padding: 0 var(--padding-xs);
|
||||
|
||||
&:focus {
|
||||
.list-row {
|
||||
background-color: var(--highlight-color);
|
||||
}
|
||||
}
|
||||
|
||||
.list-row-border {
|
||||
border-bottom: 1px solid $border-color;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
&:last-child .list-row-border {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.list-row {
|
||||
padding: 15px 15px 15px 0px;
|
||||
height: 38px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
-webkit-transition: color 0.2s;
|
||||
|
|
@ -149,10 +157,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.select-like,
|
||||
.file-select {
|
||||
padding-left: 11px;
|
||||
}
|
||||
|
||||
.select-like {
|
||||
padding: 10px 0 10px 11px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-row-head {
|
||||
|
|
@ -160,8 +171,7 @@
|
|||
cursor: default;
|
||||
background-color: var(--subtle-fg);
|
||||
height: 30px;
|
||||
padding: 8px, 10px, 8px, 0px;
|
||||
margin: 8px 5px 0px 5px;
|
||||
margin: 0.5rem var(--padding-xs);
|
||||
border-radius: var(--border-radius-md);
|
||||
|
||||
.list-check-all {
|
||||
|
|
@ -246,6 +256,7 @@ input.list-row-checkbox {
|
|||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
--checkbox-right-margin: calc(var(--checkbox-size) / 2 + #{$level-margin-right});
|
||||
background-color: var(--card-bg);
|
||||
}
|
||||
|
||||
input.list-check-all {
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@
|
|||
|
||||
.page-form {
|
||||
margin: 0;
|
||||
padding: var(--padding-sm);
|
||||
padding: var(--padding-xs);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background-color: var(--card-bg);
|
||||
|
|
|
|||
|
|
@ -164,6 +164,23 @@
|
|||
frappe._messages = {{ translated_messages }};
|
||||
frappe.web_form_doc = {{ web_form_doc | json }};
|
||||
frappe.reference_doc = {{ reference_doc | json }};
|
||||
function in_iframe() {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (in_iframe()) {
|
||||
// hide everything except the form and fix styles
|
||||
$('nav').hide();
|
||||
$('.web-form-header').hide();
|
||||
$('.page-footer').hide();
|
||||
$('footer').hide();
|
||||
$('.page-breadcrumbs').hide();
|
||||
$('.web-form').css('border', 'none').css('padding', 'unset');
|
||||
$('.page_content').css('padding-left', 'unset').css('padding-right', 'unset');
|
||||
}
|
||||
</script>
|
||||
{{ include_script("web_form.bundle.js") }}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,16 @@ frappe.ui.form.on("Web Form", {
|
|||
},
|
||||
|
||||
refresh: function (frm) {
|
||||
// get iframe url for web form
|
||||
frm.sidebar
|
||||
.add_user_action(__("Copy Embed Code"))
|
||||
.attr("href", "#")
|
||||
.on("click", () => {
|
||||
const url = frappe.urllib.get_full_url(frm.doc.route);
|
||||
const code = `<iframe src="${url}" style="border: none; width: 100%; height: inherit;"></iframe>`;
|
||||
frappe.utils.copy_to_clipboard(code, __("Embed code copied"));
|
||||
});
|
||||
|
||||
if (frm.doc.is_standard && !frappe.boot.developer_mode) {
|
||||
frm.disable_form();
|
||||
frappe.show_alert(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "templates/web.html" %}
|
||||
|
||||
{% set title = heading or "Contact Us" %}
|
||||
{% block header %}<h1>{{ heading or "Contact Us" }}</h1>{% endblock %}
|
||||
{% block header %}<h1>{{ heading or _("Contact Us") }}</h1>{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<style>
|
||||
|
|
@ -23,10 +23,10 @@
|
|||
<select name="subject" class="form-control">
|
||||
{% if query_options -%}
|
||||
{% for option in query_options.split("\n") -%}
|
||||
<option value="{{ option }}">{{ option }}</option>
|
||||
<option value="{{ option }}">{{ _(option) }}</option>
|
||||
{%- endfor %}
|
||||
{% else %}
|
||||
<option value="General">General</option>
|
||||
<option value="General">{{ _("General") }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -34,20 +34,29 @@ def send_message(sender, message, subject="Website Query"):
|
|||
if forward_to_email := frappe.db.get_single_value("Contact Us Settings", "forward_to_email"):
|
||||
frappe.sendmail(recipients=forward_to_email, reply_to=sender, content=message, subject=subject)
|
||||
|
||||
reply = _(
|
||||
"""Thank you for reaching out to us. We will get back to you at the earliest.
|
||||
|
||||
|
||||
Your query:
|
||||
|
||||
{0}"""
|
||||
).format(message)
|
||||
frappe.sendmail(
|
||||
recipients=sender,
|
||||
content=f"<div style='white-space: pre-wrap'>Thank you for reaching out to us. We will get back to you at the earliest.\n\n\nYour query:\n\n{message}</div>",
|
||||
subject="We've received your query!",
|
||||
content=f"<div style='white-space: pre-wrap'>{reply}</div>",
|
||||
subject=_("We've received your query!"),
|
||||
)
|
||||
|
||||
# for clearing outgoing email error message
|
||||
frappe.clear_last_message()
|
||||
|
||||
system_language = frappe.db.get_single_value("System Settings", "language")
|
||||
# add to to-do ?
|
||||
frappe.get_doc(
|
||||
doctype="Communication",
|
||||
sender=sender,
|
||||
subject=_("New Message from Website Contact Page"),
|
||||
subject=_("New Message from Website Contact Page", system_language),
|
||||
sent_or_received="Received",
|
||||
content=message,
|
||||
status="Open",
|
||||
|
|
|
|||
|
|
@ -155,8 +155,12 @@ def _generate_temporary_login_link(email: str, expiry: int):
|
|||
return get_url(f"/api/method/frappe.www.login.login_via_key?key={key}")
|
||||
|
||||
|
||||
def get_login_with_email_link_ratelimit() -> int:
|
||||
return frappe.get_system_settings("rate_limit_email_link_login") or 5
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True, methods=["GET"])
|
||||
@rate_limit(limit=5, seconds=60 * 60)
|
||||
@rate_limit(limit=get_login_with_email_link_ratelimit, seconds=60 * 60)
|
||||
def login_via_key(key: str):
|
||||
cache_key = f"one_time_login_key:{key}"
|
||||
email = frappe.cache.get_value(cache_key)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue