feat!: remove the "Transaction Log" DocType and a related report (#33844)
This commit is contained in:
parent
7ac00507ae
commit
6aed5b91d3
11 changed files with 1 additions and 428 deletions
|
|
@ -1,16 +0,0 @@
|
|||
# Transaction Log Changelog
|
||||
|
||||
## v1.0.0
|
||||
Initial version
|
||||
|
||||
The line hash summarizes:
|
||||
- The index of the row
|
||||
- The timestamp
|
||||
- The document raw data
|
||||
|
||||
The chain hash summarizes:
|
||||
- The previous line hash
|
||||
- The current line hash
|
||||
|
||||
## v1.0.1
|
||||
Modification of the timestamp fieldtype from "Time" to "Datetime"
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
# Copyright (c) 2018, Frappe Technologies and Contributors
|
||||
# License: MIT. See LICENSE
|
||||
import hashlib
|
||||
|
||||
import frappe
|
||||
from frappe.tests import IntegrationTestCase
|
||||
|
||||
|
||||
class TestTransactionLog(IntegrationTestCase):
|
||||
def test_validate_chaining(self):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Transaction Log",
|
||||
"reference_doctype": "Test Doctype",
|
||||
"document_name": "Test Document 1",
|
||||
"data": "first_data",
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
second_log = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Transaction Log",
|
||||
"reference_doctype": "Test Doctype",
|
||||
"document_name": "Test Document 2",
|
||||
"data": "second_data",
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
third_log = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Transaction Log",
|
||||
"reference_doctype": "Test Doctype",
|
||||
"document_name": "Test Document 3",
|
||||
"data": "third_data",
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
sha = hashlib.sha256()
|
||||
sha.update(
|
||||
frappe.safe_encode(str(third_log.transaction_hash))
|
||||
+ frappe.safe_encode(str(second_log.chaining_hash))
|
||||
)
|
||||
|
||||
self.assertEqual(sha.hexdigest(), third_log.chaining_hash)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
// Copyright (c) 2018, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Transaction Log", {});
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2018-02-06 11:48:51.270524",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"row_index",
|
||||
"section_break_2",
|
||||
"reference_doctype",
|
||||
"document_name",
|
||||
"column_break_5",
|
||||
"timestamp",
|
||||
"checksum_version",
|
||||
"section_break_8",
|
||||
"previous_hash",
|
||||
"transaction_hash",
|
||||
"chaining_hash",
|
||||
"data",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "row_index",
|
||||
"fieldtype": "Data",
|
||||
"label": "Row Index",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_doctype",
|
||||
"fieldtype": "Data",
|
||||
"label": "Reference Document Type",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "document_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Document Name",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "timestamp",
|
||||
"fieldtype": "Datetime",
|
||||
"label": "Timestamp",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "checksum_version",
|
||||
"fieldtype": "Data",
|
||||
"label": "Checksum Version",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "previous_hash",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
"label": "Previous Hash",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "transaction_hash",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Transaction Hash",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "chaining_hash",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
"label": "Chaining Hash",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "data",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 1,
|
||||
"label": "Data",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Transaction Log",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"in_create": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-23 16:03:59.373102",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Transaction Log",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Administrator",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
# Copyright (c) 2021, Frappe Technologies and contributors
|
||||
# License: MIT. See LICENSE
|
||||
|
||||
import hashlib
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.query_builder import DocType
|
||||
from frappe.utils import cint, now_datetime
|
||||
|
||||
|
||||
class TransactionLog(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
|
||||
|
||||
amended_from: DF.Link | None
|
||||
chaining_hash: DF.SmallText | None
|
||||
checksum_version: DF.Data | None
|
||||
data: DF.LongText | None
|
||||
document_name: DF.Data | None
|
||||
previous_hash: DF.SmallText | None
|
||||
reference_doctype: DF.Data | None
|
||||
row_index: DF.Data | None
|
||||
timestamp: DF.Datetime | None
|
||||
transaction_hash: DF.SmallText | None
|
||||
# end: auto-generated types
|
||||
|
||||
def before_insert(self):
|
||||
index = get_current_index()
|
||||
self.row_index = index
|
||||
self.timestamp = now_datetime()
|
||||
if index != 1:
|
||||
prev_hash = frappe.get_all(
|
||||
"Transaction Log", filters={"row_index": str(index - 1)}, pluck="chaining_hash", limit=1
|
||||
)
|
||||
if prev_hash:
|
||||
self.previous_hash = prev_hash[0]
|
||||
else:
|
||||
self.previous_hash = "Indexing broken"
|
||||
else:
|
||||
self.previous_hash = self.hash_line()
|
||||
self.transaction_hash = self.hash_line()
|
||||
self.chaining_hash = self.hash_chain()
|
||||
self.checksum_version = "v1.0.1"
|
||||
|
||||
def hash_line(self):
|
||||
sha = hashlib.sha256()
|
||||
sha.update(
|
||||
frappe.safe_encode(str(self.row_index))
|
||||
+ frappe.safe_encode(str(self.timestamp))
|
||||
+ frappe.safe_encode(str(self.data))
|
||||
)
|
||||
return sha.hexdigest()
|
||||
|
||||
def hash_chain(self):
|
||||
sha = hashlib.sha256()
|
||||
sha.update(
|
||||
frappe.safe_encode(str(self.transaction_hash)) + frappe.safe_encode(str(self.previous_hash))
|
||||
)
|
||||
return sha.hexdigest()
|
||||
|
||||
|
||||
def get_current_index():
|
||||
series = DocType("Series")
|
||||
current = (
|
||||
frappe.qb.from_(series).where(series.name == "TRANSACTLOG").for_update().select("current")
|
||||
).run()
|
||||
|
||||
if current and current[0][0] is not None:
|
||||
current = current[0][0]
|
||||
|
||||
frappe.db.sql(
|
||||
"""UPDATE `tabSeries`
|
||||
SET `current` = `current` + 1
|
||||
where `name` = 'TRANSACTLOG'"""
|
||||
)
|
||||
current = cint(current) + 1
|
||||
else:
|
||||
frappe.db.sql("INSERT INTO `tabSeries` (name, current) VALUES ('TRANSACTLOG', 1)")
|
||||
current = 1
|
||||
return current
|
||||
|
|
@ -22,7 +22,7 @@ from frappe.permissions import (
|
|||
)
|
||||
from frappe.utils.user import get_users_with_role as _get_user_with_role
|
||||
|
||||
not_allowed_in_permission_manager = ["DocType", "Patch Log", "Module Def", "Transaction Log"]
|
||||
not_allowed_in_permission_manager = ["DocType", "Patch Log", "Module Def"]
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright (c) 2019, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.query_reports["Transaction Log Report"] = {
|
||||
onload: function (query_report) {
|
||||
query_report.add_make_chart_button = function () {
|
||||
//
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2018-03-15 18:37:48.783779",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2018-12-27 18:10:29.785415",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Transaction Log Report",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Transaction Log",
|
||||
"report_name": "Transaction Log Report",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Administrator"
|
||||
},
|
||||
{
|
||||
"role": "System Manager"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
# Copyright (c) 2021, Frappe Technologies and contributors
|
||||
# License: MIT. See LICENSE
|
||||
|
||||
import hashlib
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import format_datetime
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
columns, data = get_columns(filters), get_data(filters)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_data(filters=None):
|
||||
result = []
|
||||
logs = frappe.get_all("Transaction Log", fields=["*"], order_by="creation desc")
|
||||
|
||||
for l in logs:
|
||||
row_index = int(l.row_index)
|
||||
if row_index > 1:
|
||||
previous_hash = frappe.get_all(
|
||||
"Transaction Log",
|
||||
fields=["chaining_hash"],
|
||||
filters={"row_index": row_index - 1},
|
||||
)
|
||||
if not previous_hash:
|
||||
integrity = False
|
||||
else:
|
||||
integrity = check_data_integrity(
|
||||
l.chaining_hash, l.transaction_hash, l.previous_hash, previous_hash[0]["chaining_hash"]
|
||||
)
|
||||
|
||||
result.append(
|
||||
[
|
||||
_(str(integrity)),
|
||||
_(l.reference_doctype),
|
||||
l.document_name,
|
||||
l.owner,
|
||||
l.modified_by,
|
||||
format_datetime(l.timestamp, "YYYYMMDDHHmmss"),
|
||||
]
|
||||
)
|
||||
else:
|
||||
result.append(
|
||||
[
|
||||
_("First Transaction"),
|
||||
_(l.reference_doctype),
|
||||
l.document_name,
|
||||
l.owner,
|
||||
l.modified_by,
|
||||
format_datetime(l.timestamp, "YYYYMMDDHHmmss"),
|
||||
]
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def check_data_integrity(chaining_hash, transaction_hash, registered_previous_hash, previous_hash):
|
||||
if registered_previous_hash != previous_hash:
|
||||
return False
|
||||
|
||||
calculated_chaining_hash = calculate_chain(transaction_hash, previous_hash)
|
||||
|
||||
if calculated_chaining_hash != chaining_hash:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def calculate_chain(transaction_hash, previous_hash):
|
||||
sha = hashlib.sha256()
|
||||
sha.update(transaction_hash.encode("utf-8") + previous_hash.encode("utf-8"))
|
||||
return sha.hexdigest()
|
||||
|
||||
|
||||
def get_columns(filters=None):
|
||||
return [
|
||||
{
|
||||
"label": _("Chain Integrity"),
|
||||
"fieldname": "chain_integrity",
|
||||
"fieldtype": "Data",
|
||||
"width": 150,
|
||||
},
|
||||
{
|
||||
"label": _("Reference Doctype"),
|
||||
"fieldname": "reference_doctype",
|
||||
"fieldtype": "Data",
|
||||
"width": 150,
|
||||
},
|
||||
{
|
||||
"label": _("Reference Name"),
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Data",
|
||||
"width": 150,
|
||||
},
|
||||
{
|
||||
"label": _("Owner"),
|
||||
"fieldname": "owner",
|
||||
"fieldtype": "Data",
|
||||
"width": 100,
|
||||
},
|
||||
{
|
||||
"label": _("Modified By"),
|
||||
"fieldname": "modified_by",
|
||||
"fieldtype": "Data",
|
||||
"width": 100,
|
||||
},
|
||||
{
|
||||
"label": _("Timestamp"),
|
||||
"fieldname": "timestamp",
|
||||
"fieldtype": "Data",
|
||||
"width": 100,
|
||||
},
|
||||
]
|
||||
Loading…
Add table
Reference in a new issue