Merge pull request #19780 from ankush/hooks_audit

feat: Audit hooks report
This commit is contained in:
Ankush Menat 2023-01-29 20:14:32 +05:30 committed by GitHub
commit 87008e3930
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 121 additions and 0 deletions

View file

View file

@ -0,0 +1,7 @@
// Copyright (c) 2023, Frappe Technologies and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Audit System Hooks"] = {
filters: [],
};

View file

@ -0,0 +1,27 @@
{
"add_total_row": 0,
"columns": [],
"creation": "2023-01-25 15:02:21.896117",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2023-01-25 15:03:31.263337",
"modified_by": "Administrator",
"module": "Custom",
"name": "Audit System Hooks",
"owner": "Administrator",
"prepared_report": 0,
"query": "",
"ref_doctype": "System Settings",
"report_name": "Audit System Hooks",
"report_type": "Script Report",
"roles": [
{
"role": "System Manager"
}
]
}

View file

@ -0,0 +1,70 @@
# Copyright (c) 2023, Frappe Technologies and contributors
# For license information, please see license.txt
import frappe
def execute(filters=None):
return get_columns(), get_data()
def get_columns():
values_field_type = "Data" # TODO: better text wrapping in reportview
columns = [
{"label": "Hook name", "fieldname": "hook_name", "fieldtype": "Data", "width": 200},
{"label": "Hook key (optional)", "fieldname": "hook_key", "fieldtype": "Data", "width": 200},
{"label": "Hook Values (resolved)", "fieldname": "hook_values", "fieldtype": values_field_type},
]
# Each app is shown in order as a column
installed_apps = frappe.get_installed_apps(_ensure_on_bench=True)
columns += [
{"label": app, "fieldname": app, "fieldtype": values_field_type} for app in installed_apps
]
return columns
def get_data():
hooks = frappe.get_hooks()
installed_apps = frappe.get_installed_apps(_ensure_on_bench=True)
def fmt_hook_values(v):
"""Improve readability by discarding falsy values and removing containers when only 1
value is in container"""
if not v:
return ""
v = delist(v)
if isinstance(v, (dict, list)):
try:
return frappe.as_json(v)
except Exception:
pass
return str(v)
data = []
for hook, values in hooks.items():
if isinstance(values, dict):
for k, v in values.items():
row = {"hook_name": hook, "hook_key": fmt_hook_values(k), "hook_values": fmt_hook_values(v)}
for app in installed_apps:
if app_hooks := delist(frappe.get_hooks(hook, app_name=app)):
row[app] = fmt_hook_values(app_hooks.get(k))
data.append(row)
else:
row = {"hook_name": hook, "hook_values": fmt_hook_values(values)}
for app in installed_apps:
row[app] = fmt_hook_values(frappe.get_hooks(hook, app_name=app))
data.append(row)
return data
def delist(val):
if isinstance(val, list) and len(val) == 1:
return val[0]
return val

View file

@ -0,0 +1,17 @@
# Copyright (c) 2022, Frappe Technologies and contributors
# For license information, please see license.txt
from frappe.custom.report.audit_system_hooks.audit_system_hooks import execute
from frappe.tests.utils import FrappeTestCase
class TestAuditSystemHooksReport(FrappeTestCase):
def test_basic_query(self):
_, data = execute()
for row in data:
if row.get("hook_name") == "app_name":
self.assertEqual(row.get("hook_values"), "frappe")
break
else:
self.fail("Failed to generate hooks report")