feat: evaluate Web Form dynamic filters server-side

This commit is contained in:
UmakanthKaspa 2026-02-15 11:03:16 +05:30
parent d0d7ef8ae6
commit 6dd4539002
4 changed files with 51 additions and 35 deletions

View file

@ -116,40 +116,6 @@ export default class WebFormList {
this.filters = Object.assign(this.filters, JSON.parse(filter));
}
if (this.dynamic_filters_json) {
let dynamic_filters = JSON.parse(this.dynamic_filters_json);
if (dynamic_filters.length) {
dynamic_filters.forEach((f) => {
let expression = f[3];
try {
f[3] = eval(f[3]);
} catch (e) {
frappe.throw(
__("Invalid expression set in filter {0} ({1}): {2}", [
f[1],
f[0],
expression,
])
);
}
if (f[3] == null) {
frappe.throw(
__("Invalid expression set in filter {0} ({1}): {2}", [
f[1],
f[0],
expression,
])
);
}
});
let df_obj = {};
dynamic_filters.forEach((f) => {
df_obj[f[1]] = [f[2], f[3]];
});
this.filters = Object.assign(this.filters, df_obj);
}
}
let args = {
method: "frappe.www.list.get_list_data",
args: {

View file

@ -28,7 +28,6 @@ frappe.ready(function () {
web_form_name: web_form_doc.name,
list_columns: web_form_doc.list_columns,
condition_json: web_form_doc.condition_json,
dynamic_filters_json: web_form_doc.dynamic_filters_json,
settings: {
allow_delete: web_form_doc.allow_delete,
},

View file

@ -346,6 +346,18 @@ frappe.ui.form.on("Web Form", {
frm.dynamic_filters
);
// Override description to show Python expressions (evaluated server-side)
let desc_field = fields.find((f) => f.fieldname === "description");
if (desc_field) {
desc_field.options = `<div>
<p>${__("Set dynamic filter values as Python expressions.")}</p>
<p>${__("For example:")}
<code>frappe.session.user</code> ${__("or")}
<code>frappe.utils.now()</code>
</p>
</div>`;
}
frm.dynamic_filter_table.on("click", () => {
if (!frm.has_perm("write")) {
return;

View file

@ -45,6 +45,11 @@ def get_list_data(
if list_context.filters:
filters.update(list_context.filters)
if web_form_name:
dynamic_filters = get_dynamic_filters(web_form_name)
if dynamic_filters:
filters.update(dynamic_filters)
_get_list = list_context.get_list or get_list
kwargs = dict(
@ -192,3 +197,37 @@ def get_list(
order_by=order_by,
distinct=distinct,
)
def get_dynamic_filters(web_form_name):
"""Evaluate dynamic filter expressions from Web Form.
Uses same safe_eval + get_workflow_safe_globals pattern as Workflow."""
from frappe.model.workflow import get_workflow_safe_globals
web_form = frappe.get_cached_doc("Web Form", web_form_name)
if not web_form.dynamic_filters_json:
return None
dynamic_filters = json.loads(web_form.dynamic_filters_json)
if not dynamic_filters:
return None
safe_globals = get_workflow_safe_globals()
safe_globals["frappe"]["defaults"] = frappe._dict(
get_user_default=frappe.defaults.get_user_default,
get_global_default=frappe.defaults.get_global_default,
)
evaluated = {}
for f in dynamic_filters:
try:
value = frappe.safe_eval(f[3], safe_globals)
evaluated[f[1]] = [f[2], value]
except Exception as e:
frappe.throw(
_("Invalid expression in Web Form Dynamic Filter for {0}: {1}").format(f[1], e),
title=_("Dynamic Filter Error"),
)
return evaluated