Skip to content

Commit

Permalink
Merge pull request #24379 from frappe/version-14-hotfix
Browse files Browse the repository at this point in the history
chore: release v14
  • Loading branch information
ankush committed Jan 16, 2024
2 parents a9c8a1d + f7a0237 commit e56597c
Show file tree
Hide file tree
Showing 35 changed files with 179 additions and 140 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/create-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 20
- name: Setup dependencies
run: |
npm install @semantic-release/git @semantic-release/exec --no-save
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,4 @@ jobs:
- run: |
pip install pip-audit
cd ${GITHUB_WORKSPACE}
sed -i '/dropbox/d' pyproject.toml # Remove dropbox temporarily https://github.com/dropbox/dropbox-sdk-python/pull/456
pip-audit --desc on --ignore-vuln GHSA-4xqq-73wg-5mjp .
4 changes: 2 additions & 2 deletions frappe/contacts/doctype/contact/test_records.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
],
"phone_nos": [
{
"phone": "+91 0000000000",
"phone": "+91 0000000001",
"is_primary_phone": 1
}
]
}
]
]
1 change: 1 addition & 0 deletions frappe/core/doctype/data_import/data_import.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ frappe.ui.form.on("Data Import", {
}
} else {
let messages = JSON.parse(log.messages || "[]")
.map(JSON.parse)
.map((m) => {
let title = m.title ? `<strong>${m.title}</strong>` : "";
let message = m.message ? `<div>${m.message}</div>` : "";
Expand Down
5 changes: 3 additions & 2 deletions frappe/core/doctype/rq_job/rq_job.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"actions": [],
"allow_copy": 1,
"autoname": "field:job_id",
"creation": "2022-09-10 16:19:37.934903",
"creation": "2023-03-22 20:05:22.962044",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
Expand Down Expand Up @@ -104,10 +104,11 @@
"fieldtype": "Section Break"
}
],
"hide_toolbar": 1,
"in_create": 1,
"is_virtual": 1,
"links": [],
"modified": "2022-09-11 05:27:50.878534",
"modified": "2024-01-13 10:38:40.230972",
"modified_by": "Administrator",
"module": "Core",
"name": "RQ Job",
Expand Down
3 changes: 2 additions & 1 deletion frappe/core/doctype/rq_worker/rq_worker.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@
"label": "Utilization %"
}
],
"hide_toolbar": 1,
"in_create": 1,
"is_virtual": 1,
"links": [],
"modified": "2022-11-24 14:50:48.511706",
"modified": "2024-01-13 10:36:13.034784",
"modified_by": "Administrator",
"module": "Core",
"name": "RQ Worker",
Expand Down
9 changes: 9 additions & 0 deletions frappe/core/doctype/rq_worker/rq_worker_list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
frappe.listview_settings["RQ Worker"] = {
refresh(listview) {
listview.$no_result.html(`
<div class="no-result text-muted flex justify-center align-center">
${__("No RQ Workers connected. Try restarting the bench.")}
</div>
`);
},
};
5 changes: 4 additions & 1 deletion frappe/desk/desktop.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,11 @@ def get_workspace_sidebar_items():
blocked_modules = frappe.get_doc("User", frappe.session.user).get_blocked_modules()
blocked_modules.append("Dummy Module")

# adding None to allowed_domains to include pages without domain restriction
allowed_domains = [None] + frappe.get_active_domains()

filters = {
"restrict_to_domain": ["in", frappe.get_active_domains()],
"restrict_to_domain": ["in", allowed_domains],
"module": ["not in", blocked_modules],
}

Expand Down
5 changes: 3 additions & 2 deletions frappe/desk/doctype/dashboard_chart/dashboard_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def get(
refresh=None,
):
if chart_name:
chart = frappe.get_doc("Dashboard Chart", chart_name)
chart: DashboardChart = frappe.get_doc("Dashboard Chart", chart_name)
else:
chart = frappe._dict(frappe.parse_json(chart))

Expand Down Expand Up @@ -207,13 +207,14 @@ def get_chart_config(chart, filters, timespan, timegrain, from_date, to_date):
filters.append([doctype, datefield, ">=", from_date, False])
filters.append([doctype, datefield, "<=", to_date, False])

data = frappe.db.get_list(
data = frappe.get_list(
doctype,
fields=[f"{datefield} as _unit", f"SUM({value_field})", "COUNT(*)"],
filters=filters,
group_by="_unit",
order_by="_unit asc",
as_list=True,
parent_doctype=chart.parent_document_type,
)

result = get_result(data, timegrain, from_date, to_date, chart.chart_type)
Expand Down
5 changes: 5 additions & 0 deletions frappe/desk/doctype/workspace/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
from frappe.modules.export_file import delete_folder, export_to_files
from frappe.utils import strip_html


class Workspace(Document):
def validate(self):
self.title = strip_html(self.title)

if self.public and not is_workspace_manager() and not disable_saving_as_public():
frappe.throw(_("You need to be Workspace Manager to edit this document"))
if self.has_value_changed("title"):
Expand Down Expand Up @@ -224,6 +227,8 @@ def save_page(title, public, new_widgets, blocks):
pages = frappe.get_all("Workspace", filters=filters)
if pages:
doc = frappe.get_doc("Workspace", pages[0])
else:
frappe.throw(_("Workspace not found"), frappe.DoesNotExistError)

doc.content = blocks
doc.save(ignore_permissions=True)
Expand Down
2 changes: 2 additions & 0 deletions frappe/email/doctype/email_account/email_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@ def handle_incoming_connect_error(self, description):
self.set_failed_attempts_count(self.get_failed_attempts_count() + 1)

def _disable_broken_incoming_account(self, description):
if frappe.flags.in_test:
return
self.db_set("enable_incoming", 0)

for user in get_system_managers(only_name=True):
Expand Down
18 changes: 11 additions & 7 deletions frappe/email/doctype/email_account/test_email_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@
from frappe.email.doctype.email_account.email_account import notify_unreplied
from frappe.email.email_body import get_message_id
from frappe.email.receive import Email, InboundMail, SentEmailInInboxError
from frappe.test_runner import make_test_records
from frappe.tests.utils import FrappeTestCase

make_test_records("User")
make_test_records("Email Account")


class TestEmailAccount(FrappeTestCase):
@classmethod
Expand Down Expand Up @@ -65,9 +61,18 @@ def test_incoming(self):
self.assertTrue(frappe.db.get_value(comm.reference_doctype, comm.reference_name, "name"))

def test_unread_notification(self):
self.test_incoming()
todo = frappe.get_last_doc("ToDo")

comm = frappe.get_doc("Communication", {"sender": "test_sender@example.com"})
comm = frappe.get_doc(
doctype="Communication",
sender="test_sender@example.com",
subject="test unread reminder",
sent_or_received="Received",
reference_doctype=todo.doctype,
reference_name=todo.name,
email_account="_Test Email Account 1",
)
comm.insert()
comm.db_set("creation", datetime.now() - timedelta(seconds=30 * 60))

frappe.db.delete("Email Queue")
Expand All @@ -78,7 +83,6 @@ def test_unread_notification(self):
{
"reference_doctype": comm.reference_doctype,
"reference_name": comm.reference_name,
"status": "Not Sent",
},
)
)
Expand Down
9 changes: 5 additions & 4 deletions frappe/model/db_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,14 +522,13 @@ def check_read_permission(self, doctype: str, parent_doctype: str | None = None)

def _set_permission_map(self, doctype: str, parent_doctype: str | None = None):
ptype = "select" if frappe.only_has_select_perm(doctype) else "read"
val = frappe.has_permission(
frappe.has_permission(
doctype,
ptype=ptype,
parent_doctype=parent_doctype or self.doctype,
throw=True,
user=self.user,
)
if not val:
frappe.flags.error_message = _("Insufficient Permission for {0}").format(frappe.bold(doctype))
raise frappe.PermissionError(doctype)
self.permission_map[doctype] = ptype

def set_field_tables(self):
Expand Down Expand Up @@ -1059,6 +1058,8 @@ def set_order_by(self, args):
self.fields[0].lower().startswith("count(")
or self.fields[0].lower().startswith("min(")
or self.fields[0].lower().startswith("max(")
or self.fields[0].lower().startswith("sum(")
or self.fields[0].lower().startswith("avg(")
)
and not self.group_by
)
Expand Down
53 changes: 23 additions & 30 deletions frappe/model/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,41 +394,34 @@ def update_children(self):

def update_child_table(self, fieldname, df=None):
"""sync child table for given fieldname"""
rows = []
if not df:
df = self.meta.get_field(fieldname)

for d in self.get(df.fieldname):
d.db_update()
rows.append(d.name)
df = df or self.meta.get_field(fieldname)
all_rows = self.get(df.fieldname)

if (
df.options in (self.flags.ignore_children_type or [])
# delete rows that do not match the ones in the document
# if the doctype isn't in ignore_children_type flag and isn't virtual
if not (
df.options in (self.flags.ignore_children_type or ())
or frappe.get_meta(df.options).is_virtual == 1
):
# do not delete rows for this because of flags
# hack for docperm :(
return

if rows:
# select rows that do not match the ones in the document
deleted_rows = frappe.db.sql(
"""select name from `tab{}` where parent=%s
and parenttype=%s and parentfield=%s
and name not in ({})""".format(
df.options, ",".join(["%s"] * len(rows))
),
[self.name, self.doctype, fieldname] + rows,
existing_row_names = [row.name for row in all_rows if row.name and not row.is_new()]

tbl = frappe.qb.DocType(df.options)
qry = (
frappe.qb.from_(tbl)
.where(tbl.parent == self.name)
.where(tbl.parenttype == self.doctype)
.where(tbl.parentfield == fieldname)
.delete()
)
if len(deleted_rows) > 0:
# delete rows that do not match the ones in the document
frappe.db.delete(df.options, {"name": ("in", tuple(row[0] for row in deleted_rows))})

else:
# no rows found, delete all rows
frappe.db.delete(
df.options, {"parent": self.name, "parenttype": self.doctype, "parentfield": fieldname}
)
if existing_row_names:
qry = qry.where(tbl.name.notin(existing_row_names))

qry.run()

# update / insert
for d in all_rows:
d.db_update()

def get_doc_before_save(self):
return getattr(self, "_doc_before_save", None)
Expand Down
1 change: 1 addition & 0 deletions frappe/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,4 @@ frappe.desk.doctype.form_tour.patches.introduce_ui_tours
execute:frappe.delete_doc_if_exists("Workspace", "Customization")
frappe.patches.v15_0.set_file_type
frappe.core.doctype.data_import.patches.remove_stale_docfields_from_legacy_version
frappe.patches.v15_0.sanitize_workspace_titles
25 changes: 25 additions & 0 deletions frappe/patches/v15_0/sanitize_workspace_titles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import frappe
from frappe.desk.doctype.workspace.workspace import update_page
from frappe.utils import strip_html
from frappe.utils.html_utils import unescape_html


def execute():
workspaces_to_update = frappe.get_all(
"Workspace",
filters={"module": ("is", "not set")},
fields=["name", "title", "icon", "parent_page as parent", "public"],
)
for workspace in workspaces_to_update:
new_title = strip_html(unescape_html(workspace.title))

if new_title == workspace.title:
continue

workspace.title = new_title
try:
update_page(**workspace)
frappe.db.commit()

except Exception:
frappe.db.rollback()
2 changes: 1 addition & 1 deletion frappe/public/js/frappe/form/controls/base_input.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ frappe.ui.form.ControlInput = class ControlInput extends frappe.ui.form.Control
let invalid = !!this.df.invalid;
if (this.grid) {
this.$wrapper.parents(".grid-static-col").toggleClass("invalid", invalid);
this.$input.toggleClass("invalid", invalid);
this.$input?.toggleClass("invalid", invalid);
this.grid_row.columns[this.df.fieldname].is_invalid = invalid;
} else {
this.$wrapper.toggleClass("has-error", invalid);
Expand Down
1 change: 1 addition & 0 deletions frappe/public/js/frappe/form/controls/markdown_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ frappe.ui.form.ControlMarkdownEditor = class ControlMarkdownEditor extends (
}

update_preview() {
if (!this.markdown_preview) return;
const value = this.get_value() || "";
this.markdown_preview.html(frappe.markdown(value));
}
Expand Down
20 changes: 11 additions & 9 deletions frappe/public/js/frappe/form/controls/multicheck.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,17 @@ frappe.ui.form.ControlMultiCheck = class ControlMultiCheck extends frappe.ui.for
make_checkboxes() {
this.$load_state.hide();
this.$checkbox_area.empty();
this.options
.sort((a, b) => cstr(a.label).localeCompare(cstr(b.label)))
.forEach((option) => {
let checkbox = this.get_checkbox_element(option).appendTo(this.$checkbox_area);
if (option.danger) {
checkbox.find(".label-area").addClass("text-danger");
}
option.$checkbox = checkbox;
});
if (this.df.sort_options != false) {
// Sort if sort_options is undefined, null or truthy.
this.options.sort((a, b) => cstr(a.label).localeCompare(cstr(b.label)));
}
this.options.forEach((option) => {
let checkbox = this.get_checkbox_element(option).appendTo(this.$checkbox_area);
if (option.danger) {
checkbox.find(".label-area").addClass("text-danger");
}
option.$checkbox = checkbox;
});
if (this.df.select_all) {
this.setup_select_all();
}
Expand Down
2 changes: 1 addition & 1 deletion frappe/public/js/frappe/list/list_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
${comment_count}
</div>
<div class="level-item visible-xs text-right">
${this.get_indicator_dot(doc)}
${this.get_indicator_html(doc)}
</div>
`;

Expand Down
2 changes: 1 addition & 1 deletion frappe/public/js/frappe/ui/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ frappe.ui.Page = class Page {
let sidebar_toggle = $(".page-head").find(".sidebar-toggle-btn");
let sidebar_wrapper = this.wrapper.find(".layout-side-section");
if (this.disable_sidebar_toggle || !sidebar_wrapper.length) {
sidebar_toggle.remove();
sidebar_toggle.last().remove();
} else {
sidebar_toggle.attr("title", __("Toggle Sidebar")).tooltip({
delay: { show: 600, hide: 100 },
Expand Down
4 changes: 3 additions & 1 deletion frappe/public/js/frappe/ui/toolbar/awesome_bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,9 @@ frappe.search.AwesomeBar = class AwesomeBar {
var route = frappe.get_route();
if (route[0] === "List" && txt.indexOf(" in") === -1) {
// search in title field
var meta = frappe.get_meta(frappe.container.page.list_view.doctype);
const doctype = frappe.container.page?.list_view?.doctype;
if (!doctype) return;
var meta = frappe.get_meta(doctype);
var search_field = meta.title_field || "name";
var options = {};
options[search_field] = ["like", "%" + txt + "%"];
Expand Down
4 changes: 4 additions & 0 deletions frappe/public/js/frappe/views/communication.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ frappe.views.CommunicationComposer = class {

if (!this.forward && !this.recipients && this.last_email) {
this.recipients = this.last_email.sender;
// If same user replies to their own email, set recipients to last email recipients
if (this.last_email.sender == this.sender) {
this.recipients = this.last_email.recipients;
}
this.cc = this.last_email.cc;
this.bcc = this.last_email.bcc;
}
Expand Down
Loading

0 comments on commit e56597c

Please sign in to comment.