fix: apply permlevel restrictions on datafields
This commit is contained in:
parent
7f2ccef7c8
commit
321751ab5a
@ -565,70 +565,6 @@ def get_fields_meta(doctype, restricted_fieldtypes=None, as_array=False):
|
||||
return fields_meta
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_sidebar_fields(doctype, name):
|
||||
if not frappe.db.exists("CRM Fields Layout", {"dt": doctype, "type": "Side Panel"}):
|
||||
return []
|
||||
layout = frappe.get_doc("CRM Fields Layout", {"dt": doctype, "type": "Side Panel"}).layout
|
||||
|
||||
if not layout:
|
||||
return []
|
||||
|
||||
layout = json.loads(layout)
|
||||
|
||||
not_allowed_fieldtypes = [
|
||||
"Tab Break",
|
||||
"Section Break",
|
||||
"Column Break",
|
||||
]
|
||||
|
||||
fields = frappe.get_meta(doctype).fields
|
||||
fields = [field for field in fields if field.fieldtype not in not_allowed_fieldtypes]
|
||||
|
||||
doc = frappe.get_cached_doc(doctype, name)
|
||||
has_high_permlevel_fields = any(df.permlevel > 0 for df in fields)
|
||||
if has_high_permlevel_fields:
|
||||
has_read_access_to_permlevels = doc.get_permlevel_access("read")
|
||||
has_write_access_to_permlevels = doc.get_permlevel_access("write")
|
||||
|
||||
for section in layout:
|
||||
section["name"] = section.get("name") or section.get("label")
|
||||
for column in section.get("columns") if section.get("columns") else []:
|
||||
for field in column.get("fields") if column.get("fields") else []:
|
||||
field_obj = next((f for f in fields if f.fieldname == field), None)
|
||||
if field_obj:
|
||||
if field_obj.permlevel > 0:
|
||||
field_has_write_access = field_obj.permlevel in has_write_access_to_permlevels
|
||||
field_has_read_access = field_obj.permlevel in has_read_access_to_permlevels
|
||||
if not field_has_write_access and field_has_read_access:
|
||||
field_obj.read_only = 1
|
||||
if not field_has_read_access and not field_has_write_access:
|
||||
field_obj.hidden = 1
|
||||
column["fields"][column.get("fields").index(field)] = get_field_obj(field_obj)
|
||||
|
||||
fields_meta = {}
|
||||
for field in fields:
|
||||
fields_meta[field.fieldname] = field
|
||||
|
||||
return layout
|
||||
|
||||
|
||||
def get_field_obj(field):
|
||||
field = field.as_dict()
|
||||
field["placeholder"] = field.get("placeholder") or "Add " + field.label + "..."
|
||||
|
||||
if field.fieldtype == "Link":
|
||||
field["placeholder"] = field.get("placeholder") or "Select " + field.label + "..."
|
||||
elif field.fieldtype == "Select" and field.options:
|
||||
field["placeholder"] = field.get("placeholder") or "Select " + field.label + "..."
|
||||
field["options"] = [{"label": option, "value": option} for option in field.options.split("\n")]
|
||||
|
||||
if field.read_only:
|
||||
field["tooltip"] = "This field is read only and cannot be edited."
|
||||
|
||||
return field
|
||||
|
||||
|
||||
def get_assigned_users(doctype, name, default_assigned_to=None):
|
||||
assigned_users = frappe.get_all(
|
||||
"ToDo",
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-01-01 20:42:29.862890",
|
||||
"modified": "2025-01-02 22:12:51.663011",
|
||||
"modified_by": "Administrator",
|
||||
"module": "FCRM",
|
||||
"name": "CRM Fields Layout",
|
||||
@ -64,6 +64,15 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "creation",
|
||||
|
||||
@ -14,7 +14,7 @@ class CRMFieldsLayout(Document):
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_fields_layout(doctype: str, type: str):
|
||||
def get_fields_layout(doctype: str, type: str, parent_doctype: str | None = None):
|
||||
tabs = []
|
||||
layout = None
|
||||
|
||||
@ -52,11 +52,94 @@ def get_fields_layout(doctype: str, type: str):
|
||||
field = next((f for f in fields if f.fieldname == field), None)
|
||||
if field:
|
||||
field = field.as_dict()
|
||||
handle_perm_level_restrictions(field, doctype, parent_doctype)
|
||||
column["fields"][column.get("fields").index(field["fieldname"])] = field
|
||||
|
||||
return tabs or []
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_sidepanel_sections(doctype):
|
||||
if not frappe.db.exists("CRM Fields Layout", {"dt": doctype, "type": "Side Panel"}):
|
||||
return []
|
||||
layout = frappe.get_doc("CRM Fields Layout", {"dt": doctype, "type": "Side Panel"}).layout
|
||||
|
||||
if not layout:
|
||||
return []
|
||||
|
||||
layout = json.loads(layout)
|
||||
|
||||
not_allowed_fieldtypes = [
|
||||
"Tab Break",
|
||||
"Section Break",
|
||||
"Column Break",
|
||||
]
|
||||
|
||||
fields = frappe.get_meta(doctype).fields
|
||||
fields = [field for field in fields if field.fieldtype not in not_allowed_fieldtypes]
|
||||
|
||||
for section in layout:
|
||||
section["name"] = section.get("name") or section.get("label")
|
||||
for column in section.get("columns") if section.get("columns") else []:
|
||||
for field in column.get("fields") if column.get("fields") else []:
|
||||
field_obj = next((f for f in fields if f.fieldname == field), None)
|
||||
if field_obj:
|
||||
field_obj = field_obj.as_dict()
|
||||
handle_perm_level_restrictions(field_obj, doctype)
|
||||
column["fields"][column.get("fields").index(field)] = get_field_obj(field_obj)
|
||||
|
||||
fields_meta = {}
|
||||
for field in fields:
|
||||
fields_meta[field.fieldname] = field
|
||||
|
||||
return layout
|
||||
|
||||
|
||||
def handle_perm_level_restrictions(field, doctype, parent_doctype=None):
|
||||
if field.permlevel == 0:
|
||||
return
|
||||
field_has_write_access = field.permlevel in get_permlevel_access("write", doctype, parent_doctype)
|
||||
field_has_read_access = field.permlevel in get_permlevel_access("read", doctype, parent_doctype)
|
||||
|
||||
if not field_has_write_access and field_has_read_access:
|
||||
field.read_only = 1
|
||||
if not field_has_read_access and not field_has_write_access:
|
||||
field.hidden = 1
|
||||
|
||||
|
||||
def get_permlevel_access(permission_type="write", doctype=None, parent_doctype=None):
|
||||
allowed_permlevels = []
|
||||
roles = frappe.get_roles()
|
||||
|
||||
meta = frappe.get_meta(doctype)
|
||||
|
||||
if meta.istable and parent_doctype:
|
||||
meta = frappe.get_meta(parent_doctype)
|
||||
elif meta.istable and not parent_doctype:
|
||||
return [1, 0]
|
||||
|
||||
for perm in meta.permissions:
|
||||
if perm.role in roles and perm.get(permission_type) and perm.permlevel not in allowed_permlevels:
|
||||
allowed_permlevels.append(perm.permlevel)
|
||||
|
||||
return allowed_permlevels
|
||||
|
||||
|
||||
def get_field_obj(field):
|
||||
field["placeholder"] = field.get("placeholder") or "Add " + field.label + "..."
|
||||
|
||||
if field.fieldtype == "Link":
|
||||
field["placeholder"] = field.get("placeholder") or "Select " + field.label + "..."
|
||||
elif field.fieldtype == "Select" and field.options:
|
||||
field["placeholder"] = field.get("placeholder") or "Select " + field.label + "..."
|
||||
field["options"] = [{"label": option, "value": option} for option in field.options.split("\n")]
|
||||
|
||||
if field.read_only:
|
||||
field["tooltip"] = "This field is read only and cannot be edited."
|
||||
|
||||
return field
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_fields_layout(doctype: str, type: str, layout: str):
|
||||
if frappe.db.exists("CRM Fields Layout", {"dt": doctype, "type": type}):
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-01-19 21:57:02.025918",
|
||||
"modified": "2025-01-02 22:14:28.686821",
|
||||
"modified_by": "Administrator",
|
||||
"module": "FCRM",
|
||||
"name": "CRM Industry",
|
||||
@ -51,6 +51,15 @@
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@ -290,7 +290,7 @@
|
||||
"image_field": "image",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-09-17 18:36:57.289897",
|
||||
"modified": "2025-01-02 22:14:01.991054",
|
||||
"modified_by": "Administrator",
|
||||
"module": "FCRM",
|
||||
"name": "CRM Lead",
|
||||
@ -320,6 +320,15 @@
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"sender_field": "email",
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-01-19 21:56:04.702254",
|
||||
"modified": "2025-01-02 22:13:30.498404",
|
||||
"modified_by": "Administrator",
|
||||
"module": "FCRM",
|
||||
"name": "CRM Lead Source",
|
||||
@ -59,6 +59,15 @@
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-01-19 21:56:16.872924",
|
||||
"modified": "2025-01-02 22:13:43.038656",
|
||||
"modified_by": "Administrator",
|
||||
"module": "FCRM",
|
||||
"name": "CRM Lead Status",
|
||||
@ -67,6 +67,15 @@
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
|
||||
@ -170,6 +170,7 @@
|
||||
:index="index"
|
||||
:data="row"
|
||||
:doctype="doctype"
|
||||
:parentDoctype="parentDoctype"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -198,6 +199,7 @@
|
||||
v-if="showGridRowFieldsModal"
|
||||
v-model="showGridRowFieldsModal"
|
||||
:doctype="doctype"
|
||||
:parentDoctype="parentDoctype"
|
||||
/>
|
||||
<GridFieldsEditorModal
|
||||
v-if="showGridFieldsEditorModal"
|
||||
|
||||
@ -36,7 +36,13 @@
|
||||
:tabs="tabs.data"
|
||||
:doctype="_doctype"
|
||||
/>
|
||||
<FieldLayout v-else :tabs="tabs.data" :data="{}" :modal="true" :preview="true"/>
|
||||
<FieldLayout
|
||||
v-else
|
||||
:tabs="tabs.data"
|
||||
:data="{}"
|
||||
:modal="true"
|
||||
:preview="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -55,6 +61,10 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: 'CRM Lead',
|
||||
},
|
||||
parentDoctype: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['reload'])
|
||||
@ -66,12 +76,16 @@ const dirty = ref(false)
|
||||
const preview = ref(false)
|
||||
|
||||
function getParams() {
|
||||
return { doctype: _doctype.value, type: 'Grid Row' }
|
||||
return {
|
||||
doctype: _doctype.value,
|
||||
type: 'Grid Row',
|
||||
parent_doctype: props.parentDoctype,
|
||||
}
|
||||
}
|
||||
|
||||
const tabs = createResource({
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_fields_layout',
|
||||
cache: ['GridRowFieldsModal', _doctype.value],
|
||||
cache: ['GridRowFieldsModal', _doctype.value, props.parentDoctype],
|
||||
params: getParams(),
|
||||
onSuccess(data) {
|
||||
tabs.originalData = JSON.parse(JSON.stringify(data))
|
||||
|
||||
@ -41,6 +41,7 @@ const props = defineProps({
|
||||
index: Number,
|
||||
data: Object,
|
||||
doctype: String,
|
||||
parentDoctype: String,
|
||||
})
|
||||
|
||||
const { isManager } = usersStore()
|
||||
@ -50,8 +51,12 @@ const showGridRowFieldsModal = defineModel('showGridRowFieldsModal')
|
||||
|
||||
const tabs = createResource({
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_fields_layout',
|
||||
cache: ['Grid Row', props.doctype],
|
||||
params: { doctype: props.doctype, type: 'Grid Row' },
|
||||
cache: ['Grid Row', props.doctype, props.parentDoctype],
|
||||
params: {
|
||||
doctype: props.doctype,
|
||||
type: 'Grid Row',
|
||||
parent_doctype: props.parentDoctype,
|
||||
},
|
||||
auto: true,
|
||||
})
|
||||
|
||||
|
||||
@ -336,9 +336,9 @@ const rows = computed(() => {
|
||||
})
|
||||
|
||||
const sections = createResource({
|
||||
url: 'crm.api.doc.get_sidebar_fields',
|
||||
cache: ['sidePanelSections', props.contactId],
|
||||
params: { doctype: 'Contact', name: props.contactId },
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||
cache: ['sidePanelSections', 'Contact'],
|
||||
params: { doctype: 'Contact' },
|
||||
auto: true,
|
||||
transform: (data) => getParsedSections(data),
|
||||
})
|
||||
|
||||
@ -530,9 +530,9 @@ const tabs = computed(() => {
|
||||
const { tabIndex } = useActiveTabManager(tabs, 'lastDealTab')
|
||||
|
||||
const sections = createResource({
|
||||
url: 'crm.api.doc.get_sidebar_fields',
|
||||
cache: ['sidePanelSections', props.dealId],
|
||||
params: { doctype: 'CRM Deal', name: props.dealId },
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||
cache: ['sidePanelSections', 'CRM Deal'],
|
||||
params: { doctype: 'CRM Deal' },
|
||||
auto: true,
|
||||
transform: (data) => getParsedSections(data),
|
||||
})
|
||||
|
||||
@ -531,9 +531,9 @@ function validateFile(file) {
|
||||
}
|
||||
|
||||
const sections = createResource({
|
||||
url: 'crm.api.doc.get_sidebar_fields',
|
||||
cache: ['sidePanelSections', props.leadId],
|
||||
params: { doctype: 'CRM Lead', name: props.leadId },
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||
cache: ['sidePanelSections', 'CRM Lead'],
|
||||
params: { doctype: 'CRM Lead' },
|
||||
auto: true,
|
||||
})
|
||||
|
||||
|
||||
@ -348,9 +348,9 @@ const rows = computed(() => {
|
||||
})
|
||||
|
||||
const fieldsLayout = createResource({
|
||||
url: 'crm.api.doc.get_sidebar_fields',
|
||||
cache: ['fieldsLayout', props.contactId],
|
||||
params: { doctype: 'Contact', name: props.contactId },
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||
cache: ['sidePanelSections', 'Contact'],
|
||||
params: { doctype: 'Contact' },
|
||||
auto: true,
|
||||
transform: (data) => getParsedFields(data),
|
||||
})
|
||||
|
||||
@ -501,9 +501,9 @@ const tabs = computed(() => {
|
||||
const { tabIndex } = useActiveTabManager(tabs, 'lastDealTab')
|
||||
|
||||
const fieldsLayout = createResource({
|
||||
url: 'crm.api.doc.get_sidebar_fields',
|
||||
cache: ['fieldsLayout', props.dealId],
|
||||
params: { doctype: 'CRM Deal', name: props.dealId },
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||
cache: ['sidePanelSections', 'CRM Deal'],
|
||||
params: { doctype: 'CRM Deal' },
|
||||
auto: true,
|
||||
transform: (data) => getParsedFields(data),
|
||||
})
|
||||
|
||||
@ -421,9 +421,9 @@ watch(tabs, (value) => {
|
||||
})
|
||||
|
||||
const fieldsLayout = createResource({
|
||||
url: 'crm.api.doc.get_sidebar_fields',
|
||||
cache: ['fieldsLayout', props.leadId],
|
||||
params: { doctype: 'CRM Lead', name: props.leadId },
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||
cache: ['sidePanelSections', 'CRM Lead'],
|
||||
params: { doctype: 'CRM Lead' },
|
||||
auto: true,
|
||||
})
|
||||
|
||||
|
||||
@ -327,9 +327,9 @@ const _organization = ref({})
|
||||
const _address = ref({})
|
||||
|
||||
const fieldsLayout = createResource({
|
||||
url: 'crm.api.doc.get_sidebar_fields',
|
||||
cache: ['fieldsLayout', props.organizationId],
|
||||
params: { doctype: 'CRM Organization', name: props.organizationId },
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||
cache: ['sidePanelSections', 'CRM Organization'],
|
||||
params: { doctype: 'CRM Organization' },
|
||||
auto: true,
|
||||
transform: (data) => getParsedFields(data),
|
||||
})
|
||||
|
||||
@ -336,9 +336,9 @@ const _organization = ref({})
|
||||
const _address = ref({})
|
||||
|
||||
const sections = createResource({
|
||||
url: 'crm.api.doc.get_sidebar_fields',
|
||||
cache: ['sidePanelSections', props.organizationId],
|
||||
params: { doctype: 'CRM Organization', name: props.organizationId },
|
||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||
cache: ['sidePanelSections', 'CRM Organization'],
|
||||
params: { doctype: 'CRM Organization' },
|
||||
auto: true,
|
||||
transform: (data) => getParsedSections(data),
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user