refactor: fetch mask field from cache instead of meta

This commit is contained in:
Ejaaz Khan 2025-09-21 19:09:32 +05:30
parent af27ab36e4
commit 03ac6e2f75
7 changed files with 42 additions and 43 deletions

View file

@ -45,19 +45,6 @@ def get_meta(doctype, cached=True) -> "FormMeta":
# In prod don't use cached meta when explicitly requesting from DB.
meta = FormMeta(doctype, cached=frappe.conf.developer_mode)
if meta.name not in meta.special_doctypes:
meta = mask_protected_fields(meta)
return meta
def mask_protected_fields(meta):
for df in meta.fields:
if df.get("mask") and not meta.has_permlevel_access_to(
fieldname=df.fieldname, df=df, permission_type="mask"
):
# store orignal fieldtype and change fieldtype to Data
df.mask_readonly = 1
return meta
@ -89,6 +76,9 @@ class FormMeta(Meta):
for k in ASSET_KEYS:
d[k] = __dict.get(k)
# add masked fields (per-user, per-meta)
d["masked_fields"] = [df.fieldname for df in self.get_masked_fields()]
return d
def add_code(self):

View file

@ -88,11 +88,6 @@ def get_meta(doctype: "str | DocType", cached: bool = True) -> "_Meta":
meta = Meta(doctype)
if meta.name not in meta.special_doctypes:
from frappe.desk.form.meta import mask_protected_fields
meta = mask_protected_fields(meta)
key = f"doctype_meta::{meta.name}"
frappe.client_cache.set_value(key, meta)
return meta
@ -200,7 +195,26 @@ class Meta(Document):
return self._dynamic_link_fields
def get_masked_fields(self):
return self.get("fields", {"mask_readonly": 1})
import copy
if frappe.session.user == "Administrator":
return []
cache_key = f"masked_fields::{self.name}::{frappe.session.user}"
masked_fields = frappe.cache.get_value(cache_key)
if masked_fields is None:
masked_fields = []
for df in self.fields:
if df.get("mask") and not self.has_permlevel_access_to(
fieldname=df.fieldname, df=df, permission_type="mask"
):
# work on a copy instead of original df
df_copy = copy.deepcopy(df)
df_copy.mask_readonly = 1
masked_fields.append(df_copy)
frappe.cache.set_value(cache_key, masked_fields)
return masked_fields
@cached_property
def _dynamic_link_fields(self):

View file

@ -1174,11 +1174,11 @@ frappe.ui.form.Form = class FrappeForm {
}
mark_mask_fields_readonly() {
this.fields.forEach((field) => {
if (field.df.mask && field.df.mask_readonly) {
this.set_df_property(field.df.fieldname, "disabled", "1");
this.set_df_property(field.df.fieldname, "fieldtype", "Data");
}
const masked_fields = this.meta.masked_fields || [];
masked_fields.forEach((fieldname) => {
this.set_df_property(fieldname, "read_only", 1);
this.set_df_property(fieldname, "fieldtype", "Data");
});
}

View file

@ -417,7 +417,13 @@ frappe.form.get_formatter = function (fieldtype) {
};
frappe.format = function (value, df, options, doc) {
if (!df || df?.mask_readonly) df = { fieldtype: "Data" };
let mask_readonly = false;
if (df.parent) {
const mask_fields = frappe.get_meta(df.parent)?.masked_fields;
mask_readonly = mask_fields?.includes(df.fieldname);
}
if (!df || mask_readonly) df = { fieldtype: "Data" };
if (df.fieldname == "_user_tags") df = { ...df, fieldtype: "Tag" };
var fieldtype = df.fieldtype || "Data";

View file

@ -245,12 +245,6 @@ frappe.ui.form.Layout = class Layout {
}
init_field(df, parent, render = false) {
if (df.mask && df.mask_readonly) {
if (df.fieldtype !== "Data") {
df.read_only = 1;
df.fieldtype = "Data";
}
}
const fieldobj = frappe.ui.form.make_control({
df: df,
doctype: this.doctype,

View file

@ -922,7 +922,10 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
_value = _value * out_of_ratings;
}
let filterable = df?.mask_readonly ? "no-underline" : " filterable";
let masked_fields = frappe.get_meta(this.doctype).masked_fields || [];
let is_masked = masked_fields.includes(df.fieldname);
let filterable = is_masked ? "no-underline" : " filterable";
if (df.fieldtype === "Image") {
html = df.options

View file

@ -1090,22 +1090,14 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
}
update_masked_fields_in_columns(columns) {
const meta_fields = frappe.get_meta(this.report_doc?.ref_doctype).fields;
const masked_fields = frappe.get_meta(this.report_doc?.ref_doctype).masked_fields;
const masked_field_map = Object.fromEntries(
meta_fields
.filter((field) => field.mask && field.mask_readonly)
.map((field) => [field.fieldname, field])
);
// return updated columns with masked field metadata applied
return columns.map((col) => {
const masked_field = masked_field_map[col.fieldname];
if (masked_field) {
if (masked_fields.includes(col.fieldname)) {
return {
...col,
fieldtype: "Data",
options: masked_field.options,
options: [],
};
}
return col;