feat: permission log
This commit is contained in:
parent
f2cf034821
commit
847dd62ec0
24 changed files with 514 additions and 34 deletions
|
|
@ -35,3 +35,12 @@ class CustomDocPerm(Document):
|
|||
|
||||
def on_update(self):
|
||||
frappe.clear_cache(doctype=self.parent)
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
return {"for_doctype": "DocType", "for_document": self.parent}
|
||||
|
||||
|
||||
def update_custom_docperm(docperm, values):
|
||||
custom_docperm = frappe.get_doc("Custom DocPerm", docperm)
|
||||
custom_docperm.update(values)
|
||||
custom_docperm.save(ignore_permissions=True)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ class CustomRole(Document):
|
|||
if self.report and not self.ref_doctype:
|
||||
self.ref_doctype = frappe.db.get_value("Report", self.report, "ref_doctype")
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
if self.report:
|
||||
return {"for_doctype": "Report", "for_document": self.report, "fields": ["roles"]}
|
||||
return {"for_doctype": "Page", "for_document": self.page, "fields": ["roles"]}
|
||||
|
||||
|
||||
def get_custom_allowed_roles(field, name):
|
||||
allowed_roles = []
|
||||
|
|
|
|||
|
|
@ -505,6 +505,14 @@ class DocType(Document):
|
|||
if d.unique:
|
||||
d.search_index = 0
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
if self.custom and event != "after_delete":
|
||||
return {
|
||||
"fields": ("permissions", {"fields": ("fieldname", "ignore_user_permissions", "permlevel")})
|
||||
}
|
||||
|
||||
self._no_perm_log = True
|
||||
|
||||
def on_update(self):
|
||||
"""Update database schema, make controller templates if `custom` is not set and clear cache."""
|
||||
|
||||
|
|
|
|||
|
|
@ -22,3 +22,6 @@ class ModuleProfile(Document):
|
|||
from frappe.utils.modules import get_modules_from_all_apps
|
||||
|
||||
self.set_onload("all_modules", sorted(m.get("module_name") for m in get_modules_from_all_apps()))
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
return {"fields": ["block_modules"]}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ class Page(Document):
|
|||
if frappe.session.user != "Administrator" and not self.flags.ignore_permissions:
|
||||
frappe.throw(_("Only Administrator can edit"))
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
return {"fields": ["roles"]}
|
||||
|
||||
# export
|
||||
def on_update(self):
|
||||
"""
|
||||
|
|
@ -97,8 +100,8 @@ class Page(Document):
|
|||
}}"""
|
||||
)
|
||||
|
||||
def as_dict(self, no_nulls=False):
|
||||
d = super().as_dict(no_nulls=no_nulls)
|
||||
def as_dict(self, **kwargs):
|
||||
d = super().as_dict(**kwargs)
|
||||
for key in ("script", "style", "content"):
|
||||
d[key] = self.get(key)
|
||||
return d
|
||||
|
|
|
|||
0
frappe/core/doctype/permission_log/__init__.py
Normal file
0
frappe/core/doctype/permission_log/__init__.py
Normal file
75
frappe/core/doctype/permission_log/permission_log.js
Normal file
75
frappe/core/doctype/permission_log/permission_log.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2022, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Permission Log", {
|
||||
refresh: function (frm) {
|
||||
frm.events.render_changed_values(frm);
|
||||
},
|
||||
|
||||
render_changed_values: function (frm) {
|
||||
let wrapper = $(frm.fields_dict["changed_values"].wrapper).empty();
|
||||
const changes = JSON.parse(frm.doc.changes);
|
||||
let changes_table = $(`<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>${__("Field")}</td>
|
||||
<td>${__("From")}</td>
|
||||
<td>${__("To")}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="main-body"></tbody>
|
||||
</table>`);
|
||||
|
||||
Object.entries(changes["from"]).forEach(([key, value]) => {
|
||||
if (Array.isArray(value || changes["to"][key])) {
|
||||
changes_table
|
||||
.find(".main-body")
|
||||
.append(frm.events.get_child_changes(key, value, changes["to"][key]));
|
||||
} else {
|
||||
changes_table.find("tbody").append(
|
||||
$(`<tr>
|
||||
<td>${frappe.model.unscrub(key)}</td>
|
||||
<td style="word-break: break-word" class="diff-remove">${changes["from"][key]}</td>
|
||||
<td style="word-break: break-word" class="diff-add">${changes["to"][key]}</td>
|
||||
</tr>`)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
wrapper.append(changes_table);
|
||||
},
|
||||
|
||||
get_child_changes: function (field_key, from, to) {
|
||||
let child_main = $(`<tr>
|
||||
<td>${frappe.model.unscrub(field_key)}</td>
|
||||
<td class="from"></td>
|
||||
<td class="to"></td>
|
||||
</tr>`);
|
||||
|
||||
[from, to].forEach((val, index) => {
|
||||
if (!val) return;
|
||||
|
||||
let for_value = index > 0 ? "to" : "frfromom";
|
||||
let child_table = $(`<table class="table-bordered small" style="margin-bottom: 5px">
|
||||
<tbody></tbody>
|
||||
</table>`);
|
||||
|
||||
val.forEach((child_row) => {
|
||||
for (const [key, value] of Object.entries(child_row)) {
|
||||
child_table.find("tbody").append(
|
||||
$(
|
||||
`<tr>
|
||||
<td style="word-break: break-word">${frappe.model.unscrub(key)}</td>
|
||||
<td style="word-break: break-word">${value}</td>
|
||||
</tr>`
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
child_main.find(`.${for_value}`).append(child_table);
|
||||
});
|
||||
|
||||
return child_main;
|
||||
},
|
||||
});
|
||||
156
frappe/core/doctype/permission_log/permission_log.json
Normal file
156
frappe/core/doctype/permission_log/permission_log.json
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2022-11-23 14:13:55.437321",
|
||||
"default_view": "List",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"changed_by",
|
||||
"column_break_gvuy",
|
||||
"changed_at",
|
||||
"status",
|
||||
"section_break_ttv7",
|
||||
"for_doctype",
|
||||
"column_break_acow",
|
||||
"for_document",
|
||||
"section_break_6gd5",
|
||||
"reference_type",
|
||||
"column_break_8nk0",
|
||||
"reference",
|
||||
"section_break_mt9x",
|
||||
"changes",
|
||||
"changed_values"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "changed_by",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Changed by",
|
||||
"options": "User",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "changed_at",
|
||||
"fieldtype": "Datetime",
|
||||
"is_virtual": 1,
|
||||
"label": "Changed at",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "changes",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "changed_values",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Changes"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_gvuy",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_ttv7",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_acow",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_mt9x",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "section_break_6gd5",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "More Info"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_8nk0",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "for_doctype",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "For DocType",
|
||||
"options": "DocType",
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "for_document",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "For Document",
|
||||
"options": "for_doctype",
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Reference Type",
|
||||
"options": "DocType",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reference",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Reference",
|
||||
"options": "reference_type",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"label": "Status",
|
||||
"options": "Updated\nRemoved\nAdded"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-09-25 17:23:31.599897",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Permission Log",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager"
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [
|
||||
{
|
||||
"color": "Yellow",
|
||||
"title": "Updated"
|
||||
},
|
||||
{
|
||||
"color": "Red",
|
||||
"title": "Removed"
|
||||
},
|
||||
{
|
||||
"color": "Green",
|
||||
"title": "Added"
|
||||
}
|
||||
],
|
||||
"title_field": "changed_by"
|
||||
}
|
||||
150
frappe/core/doctype/permission_log/permission_log.py
Normal file
150
frappe/core/doctype/permission_log/permission_log.py
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# Copyright (c) 2022, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from typing import Optional
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class PermissionLog(Document):
|
||||
# begin: auto-generated types
|
||||
# This code is auto-generated. Do not modify anything in this block.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
changed_at: DF.Datetime | None
|
||||
changed_by: DF.Link | None
|
||||
changes: DF.Text | None
|
||||
for_doctype: DF.Link
|
||||
for_document: DF.DynamicLink
|
||||
reference: DF.DynamicLink | None
|
||||
reference_type: DF.Link | None
|
||||
status: DF.Literal["Updated", "Removed", "Added"]
|
||||
# end: auto-generated types
|
||||
|
||||
@property
|
||||
def changed_at(self):
|
||||
return self.creation
|
||||
|
||||
|
||||
def make_perm_log(doc, method=None):
|
||||
if not hasattr(doc, "get_permission_log_options"):
|
||||
return
|
||||
|
||||
params = doc.get_permission_log_options(method) or {}
|
||||
if not getattr(doc, "_no_perm_log", False):
|
||||
insert_perm_log(doc, doc.get_doc_before_save(), **params)
|
||||
|
||||
|
||||
def insert_perm_log(
|
||||
doc: Document,
|
||||
doc_before_save: Document = None,
|
||||
for_doctype: Optional["str"] = None,
|
||||
for_document: Optional["str"] = None,
|
||||
fields: Optional["list | tuple"] = None,
|
||||
):
|
||||
if frappe.flags.in_install or frappe.flags.in_migrate:
|
||||
# no need to log changes when migrating or installing app/site
|
||||
return
|
||||
|
||||
current, previous = get_changes(doc, doc_before_save, fields)
|
||||
if not previous and not current:
|
||||
return
|
||||
|
||||
status = "Updated" if doc_before_save else ("Added" if doc.flags.in_insert else "Removed")
|
||||
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Permission Log",
|
||||
"owner": frappe.session.user,
|
||||
"changed_by": frappe.session.user,
|
||||
"reference_type": for_doctype and doc.doctype,
|
||||
"reference": for_document and doc.name,
|
||||
"for_doctype": for_doctype or doc.doctype,
|
||||
"for_document": for_document or doc.name,
|
||||
"status": status,
|
||||
"changes": frappe.as_json({"from": previous, "to": current}, indent=0),
|
||||
}
|
||||
).db_insert()
|
||||
|
||||
|
||||
def get_changes(doc: Document, doc_before_save=None, fields=None):
|
||||
current_changes = get_filtered_changes(
|
||||
doc.as_dict(
|
||||
no_default_fields=True,
|
||||
no_child_table_fields=True,
|
||||
no_private_properties=True,
|
||||
),
|
||||
fields,
|
||||
)
|
||||
|
||||
if not doc_before_save:
|
||||
empty_changes = dict.fromkeys(current_changes, "")
|
||||
return (current_changes, empty_changes) if doc.flags.in_insert else (empty_changes, current_changes)
|
||||
|
||||
previous_changes = get_filtered_changes(
|
||||
doc_before_save.as_dict(
|
||||
no_default_fields=True,
|
||||
no_child_table_fields=True,
|
||||
no_private_properties=True,
|
||||
),
|
||||
fields,
|
||||
)
|
||||
|
||||
return get_changes_diff(current_changes, previous_changes)
|
||||
|
||||
|
||||
def get_changes_diff(current_changes, previous_changes):
|
||||
# TODO: track, added, removed and changed rows in child tables
|
||||
|
||||
current_values = {}
|
||||
previous_values = {}
|
||||
|
||||
for k, current_val in current_changes.items():
|
||||
if isinstance(current_val, list):
|
||||
# for child table docs
|
||||
current = {frozenset(row.items()) for row in current_val}
|
||||
previous = {frozenset(row.items()) for row in previous_changes[k]}
|
||||
if not current.symmetric_difference(previous):
|
||||
continue
|
||||
|
||||
previous_values[k] = [dict(i) for i in previous - current]
|
||||
current_val = [dict(i) for i in current - previous]
|
||||
|
||||
elif previous_changes.get(k, None) == current_val:
|
||||
continue
|
||||
|
||||
previous_values[k] = previous_values[k] if k in previous_values else previous_changes[k]
|
||||
current_values[k] = current_val
|
||||
|
||||
return current_values, previous_values
|
||||
|
||||
|
||||
def get_filtered_changes(changes, filters=None):
|
||||
def filter_child_docs(child_docs, filter_keys):
|
||||
changes = []
|
||||
for child in child_docs:
|
||||
temp = {}
|
||||
for key in filter_keys:
|
||||
temp[key] = child[key]
|
||||
changes.append(temp)
|
||||
|
||||
return changes
|
||||
|
||||
if not filters:
|
||||
return changes
|
||||
|
||||
filtered_changes = {}
|
||||
for f in filters:
|
||||
if isinstance(f, dict):
|
||||
# filtered child docs
|
||||
for field, cf in f.items():
|
||||
filtered_changes[field] = filter_child_docs(changes.get(field, []), cf)
|
||||
else:
|
||||
filtered_changes[f] = changes.get(f, None)
|
||||
|
||||
return filtered_changes
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
frappe.listview_settings["Permission Log"] = {
|
||||
hide_name_column: true,
|
||||
|
||||
onload(listview) {
|
||||
if (listview.list_view_settings) {
|
||||
listview.list_view_settings.disable_comment_count = 1;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Copyright (c) 2022, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
|
||||
class TestPermissionLog(FrappeTestCase):
|
||||
pass
|
||||
|
|
@ -95,6 +95,9 @@ class Report(Document):
|
|||
frappe.throw(_("You are not allowed to delete Standard Report"))
|
||||
delete_custom_role("report", self.name)
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
return {"fields": ["roles"]}
|
||||
|
||||
def get_columns(self):
|
||||
return [d.as_dict(no_default_fields=True, no_child_table_fields=True) for d in self.columns]
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import frappe
|
|||
from frappe.core.doctype.report.report import is_prepared_report_enabled
|
||||
from frappe.model.document import Document
|
||||
from frappe.permissions import ALL_USER_ROLE
|
||||
from frappe.utils import cint
|
||||
|
||||
|
||||
class RolePermissionforPageandReport(Document):
|
||||
|
|
@ -67,16 +66,17 @@ class RolePermissionforPageandReport(Document):
|
|||
|
||||
def update_custom_roles(self):
|
||||
args = self.get_args()
|
||||
roles = self.get_roles()
|
||||
name = frappe.db.get_value("Custom Role", args, "name")
|
||||
|
||||
args.update({"doctype": "Custom Role", "roles": self.get_roles()})
|
||||
args.update({"doctype": "Custom Role", "roles": roles})
|
||||
|
||||
if self.report:
|
||||
args.update({"ref_doctype": frappe.db.get_value("Report", self.report, "ref_doctype")})
|
||||
|
||||
if name:
|
||||
custom_role = frappe.get_doc("Custom Role", name)
|
||||
custom_role.set("roles", self.get_roles())
|
||||
custom_role.set("roles", roles)
|
||||
custom_role.save()
|
||||
else:
|
||||
frappe.get_doc(args).insert()
|
||||
|
|
|
|||
|
|
@ -39,3 +39,6 @@ class RoleProfile(Document):
|
|||
for user in users:
|
||||
user = frappe.get_doc("User", user)
|
||||
user.save() # resaving syncs roles
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
return {"fields": ["roles"]}
|
||||
|
|
|
|||
|
|
@ -778,6 +778,9 @@ class User(Document):
|
|||
if not self.time_zone:
|
||||
self.time_zone = get_system_timezone()
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
return {"fields": ("role_profile_name", "roles", "module_profile", "block_modules")}
|
||||
|
||||
def check_roles_added(self):
|
||||
if self.user_type != "System User" or self.roles or not self.is_new():
|
||||
return
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ class UserPermission(Document):
|
|||
ref_link = frappe.get_desk_link(self.doctype, overlap_exists[0].name)
|
||||
frappe.throw(_("{0} has already assigned default value for {1}.").format(ref_link, self.allow))
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
pass
|
||||
|
||||
|
||||
def send_user_permissions(bootinfo):
|
||||
bootinfo.user["user_permissions"] = get_user_permissions()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.core.doctype.custom_docperm.custom_docperm import update_custom_docperm
|
||||
from frappe.model.document import Document
|
||||
from frappe.permissions import add_permission, add_user_permission
|
||||
from frappe.utils import get_link_to_form
|
||||
|
|
@ -142,7 +143,7 @@ class UserType(Document):
|
|||
docperm = add_role_permissions(row.document_type, self.role)
|
||||
values = {perm: row.get(perm, default=0) for perm in perms}
|
||||
|
||||
frappe.db.set_value("Custom DocPerm", docperm, values)
|
||||
update_custom_docperm(docperm, values)
|
||||
|
||||
def add_select_perm_doctypes(self):
|
||||
if frappe.flags.ignore_select_perm:
|
||||
|
|
@ -176,13 +177,11 @@ class UserType(Document):
|
|||
for doctype in ["select_doctypes", "custom_select_doctypes"]:
|
||||
for row in self.get(doctype):
|
||||
docperm = add_role_permissions(row.document_type, self.role)
|
||||
frappe.db.set_value(
|
||||
"Custom DocPerm", docperm, {"select": 1, "read": 0, "create": 0, "write": 0}
|
||||
)
|
||||
update_custom_docperm(docperm, {"select": 1, "read": 0, "create": 0, "write": 0})
|
||||
|
||||
def add_role_permissions_for_file(self):
|
||||
docperm = add_role_permissions("File", self.role)
|
||||
frappe.db.set_value("Custom DocPerm", docperm, {"read": 1, "create": 1, "write": 1})
|
||||
update_custom_docperm(docperm, {"read": 1, "create": 1, "write": 1})
|
||||
|
||||
def remove_permission_for_deleted_doctypes(self):
|
||||
doctypes = [d.document_type for d in self.user_doctypes]
|
||||
|
|
@ -340,4 +339,6 @@ def apply_permissions_for_non_standard_user_type(doc, method=None):
|
|||
user_doc.update_children()
|
||||
add_user_permission(doc.doctype, doc.name, doc.get(data[1]))
|
||||
else:
|
||||
frappe.db.set_value("User Permission", perm_data[0], "user", doc.get(data[1]))
|
||||
user_perm = frappe.get_doc("User Permission", perm_data[0])
|
||||
user_perm.user = doc.get(data[1])
|
||||
user_perm.save(ignore_permissions=True)
|
||||
|
|
|
|||
|
|
@ -146,10 +146,11 @@ def remove(doctype, role, permlevel, if_owner=0):
|
|||
frappe.only_for("System Manager")
|
||||
setup_custom_perms(doctype)
|
||||
|
||||
frappe.db.delete(
|
||||
"Custom DocPerm",
|
||||
{"parent": doctype, "role": role, "permlevel": permlevel, "if_owner": if_owner},
|
||||
custom_docperms = frappe.db.get_values(
|
||||
"Custom DocPerm", {"parent": doctype, "role": role, "permlevel": permlevel, "if_owner": if_owner}
|
||||
)
|
||||
for name in custom_docperms:
|
||||
frappe.delete_doc("Custom DocPerm", name, ignore_permissions=True)
|
||||
|
||||
if not frappe.get_all("Custom DocPerm", {"parent": doctype}):
|
||||
frappe.throw(_("There must be atleast one permission rule."), title=_("Cannot Remove"))
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import json
|
|||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.custom.doctype.property_setter.property_setter import delete_property_setter
|
||||
from frappe.model import core_doctypes_list
|
||||
from frappe.model.docfield import supports_translation
|
||||
from frappe.model.document import Document
|
||||
|
|
@ -221,7 +222,7 @@ class CustomField(Document):
|
|||
)
|
||||
|
||||
# delete property setter entries
|
||||
frappe.db.delete("Property Setter", {"doc_type": self.dt, "field_name": self.fieldname})
|
||||
delete_property_setter(self.dt, field_name=self.fieldname)
|
||||
|
||||
# update doctype layouts
|
||||
doctype_layouts = frappe.get_all("DocType Layout", filters={"document_type": self.dt}, pluck="name")
|
||||
|
|
@ -248,6 +249,21 @@ class CustomField(Document):
|
|||
if self.fieldname == self.insert_after:
|
||||
frappe.throw(_("Insert After cannot be set as {0}").format(meta.get_label(self.insert_after)))
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
if event != "after_delete" and self.fieldtype not in (
|
||||
"Section Break",
|
||||
"Column Break",
|
||||
"Tab Break",
|
||||
"Fold",
|
||||
):
|
||||
return {
|
||||
"fields": ("ignore_user_permissions", "permlevel"),
|
||||
"for_doctype": "DocType",
|
||||
"for_document": self.dt,
|
||||
}
|
||||
|
||||
self._no_perm_log = True
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_fields_label(doctype=None):
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ class CustomizeForm(Document):
|
|||
property_name, json.dumps([d.name for d in self.get(fieldname)]), "Small Text"
|
||||
)
|
||||
else:
|
||||
frappe.db.delete("Property Setter", dict(property=property_name, doc_type=self.doc_type))
|
||||
delete_property_setter(self.doc_type, property=property_name)
|
||||
|
||||
def clear_removed_items(self, doctype, items):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -59,6 +59,16 @@ class PropertySetter(Document):
|
|||
|
||||
validate_fields_for_doctype(self.doc_type)
|
||||
|
||||
def get_permission_log_options(self, event=None):
|
||||
if self.property in ("ignore_user_permissions", "permlevel"):
|
||||
return {
|
||||
"for_doctype": "DocType",
|
||||
"for_document": self.doc_type,
|
||||
"fields": ("value", "property", "field_name"),
|
||||
}
|
||||
|
||||
self._no_perm_log = True
|
||||
|
||||
|
||||
def make_property_setter(
|
||||
doctype,
|
||||
|
|
@ -87,12 +97,17 @@ def make_property_setter(
|
|||
return property_setter
|
||||
|
||||
|
||||
def delete_property_setter(doc_type, property, field_name=None, row_name=None):
|
||||
def delete_property_setter(doc_type, property=None, field_name=None, row_name=None):
|
||||
"""delete other property setters on this, if this is new"""
|
||||
filters = dict(doc_type=doc_type, property=property)
|
||||
filters = {"doc_type": doc_type}
|
||||
if property:
|
||||
filters["property"] = property
|
||||
|
||||
if field_name:
|
||||
filters["field_name"] = field_name
|
||||
if row_name:
|
||||
filters["row_name"] = row_name
|
||||
|
||||
frappe.db.delete("Property Setter", filters)
|
||||
property_setters = frappe.db.get_values("Property Setter", filters)
|
||||
for ps in property_setters:
|
||||
frappe.get_doc("Property Setter", ps).delete(ignore_permissions=True)
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ doc_events = {
|
|||
"frappe.automation.doctype.assignment_rule.assignment_rule.apply",
|
||||
"frappe.automation.doctype.assignment_rule.assignment_rule.update_due_date",
|
||||
"frappe.core.doctype.user_type.user_type.apply_permissions_for_non_standard_user_type",
|
||||
"frappe.core.doctype.permission_log.permission_log.make_perm_log",
|
||||
],
|
||||
"after_rename": "frappe.desk.notifications.clear_doctype_notifications",
|
||||
"on_cancel": [
|
||||
|
|
@ -178,6 +179,7 @@ doc_events = {
|
|||
"frappe.social.doctype.energy_point_rule.energy_point_rule.process_energy_points",
|
||||
"frappe.automation.doctype.milestone_tracker.milestone_tracker.evaluate_milestone",
|
||||
],
|
||||
"after_delete": ["frappe.core.doctype.permission_log.permission_log.make_perm_log"],
|
||||
},
|
||||
"Event": {
|
||||
"after_insert": "frappe.integrations.doctype.google_calendar.google_calendar.insert_event_in_google_calendar",
|
||||
|
|
@ -422,6 +424,7 @@ ignore_links_on_delete = [
|
|||
"Workspace",
|
||||
"Route History",
|
||||
"Access Log",
|
||||
"Permission Log",
|
||||
]
|
||||
|
||||
# Request Hooks
|
||||
|
|
|
|||
|
|
@ -490,6 +490,7 @@ class BaseDocument:
|
|||
no_default_fields=False,
|
||||
convert_dates_to_str=False,
|
||||
no_child_table_fields=False,
|
||||
no_private_properties=False,
|
||||
) -> dict:
|
||||
doc = self.get_valid_dict(convert_dates_to_str=convert_dates_to_str, ignore_nulls=no_nulls)
|
||||
doc["doctype"] = self.doctype
|
||||
|
|
@ -502,6 +503,7 @@ class BaseDocument:
|
|||
no_nulls=no_nulls,
|
||||
no_default_fields=no_default_fields,
|
||||
no_child_table_fields=no_child_table_fields,
|
||||
no_private_properties=no_private_properties,
|
||||
)
|
||||
for d in children
|
||||
]
|
||||
|
|
@ -516,16 +518,17 @@ class BaseDocument:
|
|||
if key in doc:
|
||||
del doc[key]
|
||||
|
||||
for key in (
|
||||
"_user_tags",
|
||||
"__islocal",
|
||||
"__onload",
|
||||
"_liked_by",
|
||||
"__run_link_triggers",
|
||||
"__unsaved",
|
||||
):
|
||||
if value := getattr(self, key, None):
|
||||
doc[key] = value
|
||||
if not no_private_properties:
|
||||
for key in (
|
||||
"_user_tags",
|
||||
"__islocal",
|
||||
"__onload",
|
||||
"_liked_by",
|
||||
"__run_link_triggers",
|
||||
"__unsaved",
|
||||
):
|
||||
if value := getattr(self, key, None):
|
||||
doc[key] = value
|
||||
|
||||
return doc
|
||||
|
||||
|
|
|
|||
|
|
@ -614,15 +614,16 @@ def update_permission_property(
|
|||
if_owner=0,
|
||||
):
|
||||
"""Update a property in Custom Perm"""
|
||||
from frappe.core.doctype.custom_docperm.custom_docperm import update_custom_docperm
|
||||
from frappe.core.doctype.doctype.doctype import validate_permissions_for_doctype
|
||||
|
||||
out = setup_custom_perms(doctype)
|
||||
|
||||
name = frappe.db.get_value(
|
||||
"Custom DocPerm", dict(parent=doctype, role=role, permlevel=permlevel, if_owner=if_owner)
|
||||
custom_docperm = frappe.db.get_value(
|
||||
"Custom DocPerm", dict(parent=doctype, role=role, permlevel=permlevel)
|
||||
)
|
||||
table = DocType("Custom DocPerm")
|
||||
frappe.qb.update(table).set(ptype, value).where(table.name == name).run()
|
||||
if custom_docperm:
|
||||
update_custom_docperm(custom_docperm, {ptype: value})
|
||||
|
||||
if validate:
|
||||
validate_permissions_for_doctype(doctype)
|
||||
|
|
@ -690,7 +691,8 @@ def reset_perms(doctype):
|
|||
from frappe.desk.notifications import delete_notification_count_for
|
||||
|
||||
delete_notification_count_for(doctype)
|
||||
frappe.db.delete("Custom DocPerm", {"parent": doctype})
|
||||
for custom_docperm in frappe.get_all("Custom DocPerm", filters={"parent": doctype}, pluck="name"):
|
||||
frappe.delete_doc("Custom DocPerm", custom_docperm, ignore_permissions=True)
|
||||
|
||||
|
||||
def get_linked_doctypes(dt: str) -> list:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue