Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions auditlog/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,19 +112,35 @@ Contributors
------------

- Sebastien Alix <sebastien.alix@camptocamp.com>

- Holger Brunn <hbrunn@therp.nl>

- Holden Rehg <holdenrehg@gmail.com>

- Eric Lembregts <eric@lembregts.eu>

- Pieter Paulussen <pieter.paulussen@me.com>

- Alan Ramos <alan.ramos@jarsa.com.mx>

- Stefan Rijnhart <stefan@opener.amsterdam>

- Bhavesh Odedra <bodedra@opensourceintegrators.com>

- Hardik Suthar <hsuthar@opensourceintegrators.com>

- Kitti U. <kittiu@ecosoft.co.th>

- Bogdan Valentin Gabor <valentin.gabor@bt-group.com>

- Dennis Sluijk d.sluijk@onestein.nl

- Adam Heinz <adam.heinz@metricwise.com>

- `OERP Canada <https://www.oerp.ca/>`__:

- Hembert Iregui <<hi@oerp.ca>

Other credits
-------------

Expand Down
23 changes: 14 additions & 9 deletions auditlog/models/auditlog_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ def _make_create(self):

@api.model_create_multi
def create_full(self, vals_list, **kwargs):
self = self.with_context(auditlog_disabled=True)
self = self.with_context(auditlog_disabled_read=True)
rule_model = self.env["auditlog.rule"]
new_records = create_full.origin(self, vals_list, **kwargs)
# Take a snapshot of record values from the cache instead of using
Expand Down Expand Up @@ -400,7 +400,7 @@ def create_full(self, vals_list, **kwargs):

@api.model_create_multi
def create_fast(self, vals_list, **kwargs):
self = self.with_context(auditlog_disabled=True)
self = self.with_context(auditlog_disabled_read=True)
rule_model = self.env["auditlog.rule"]
vals_list = rule_model._update_vals_list(vals_list)
vals_list2 = copy.deepcopy(vals_list)
Expand Down Expand Up @@ -443,9 +443,9 @@ def read(self, fields=None, load="_classic_read", **kwargs):
# avoid logs on `read` produced by auditlog during internal
# processing: read data of relevant records, 'ir.model',
# 'ir.model.fields'... (no interest in logging such operations)
if self.env.context.get("auditlog_disabled"):
if self.env.context.get("auditlog_disabled_read"):
return result
self = self.with_context(auditlog_disabled=True)
self = self.with_context(auditlog_disabled_read=True)
rule_model = self.env["auditlog.rule"]
if self.env.user in users_to_exclude:
return result
Expand All @@ -469,7 +469,12 @@ def _make_write(self):
users_to_exclude = self.mapped("users_to_exclude_ids")

def write_full(self, vals, **kwargs):
self = self.with_context(auditlog_disabled=True)
Comment thread
hi-oerp marked this conversation as resolved.
guard = self.env.context.get("auditlog_guard", set())
guard_keys = {(self._name, tuple(self.ids))}
if bool(guard.intersection(guard_keys)):
return write_full.origin(self, vals, **kwargs)
guard.update(guard_keys)
self = self.with_context(auditlog_guard=guard, auditlog_disabled_read=True)
rule_model = self.env["auditlog.rule"]
fields_list = rule_model.get_auditlog_fields(self)
records_write = (
Expand Down Expand Up @@ -503,7 +508,7 @@ def write_full(self, vals, **kwargs):
return result

def write_fast(self, vals, **kwargs):
self = self.with_context(auditlog_disabled=True)
self = self.with_context(auditlog_disabled_read=True)
rule_model = self.env["auditlog.rule"]
# Log the user input only, no matter if the `vals` is updated
# afterwards as it could not represent the real state
Expand Down Expand Up @@ -535,7 +540,7 @@ def _make_unlink(self):
users_to_exclude = self.mapped("users_to_exclude_ids")

def unlink_full(self, **kwargs):
self = self.with_context(auditlog_disabled=True)
self = self.with_context(auditlog_disabled_read=True)
rule_model = self.env["auditlog.rule"]
fields_list = rule_model.get_auditlog_fields(self)
old_values = {
Expand All @@ -558,7 +563,7 @@ def unlink_full(self, **kwargs):
return unlink_full.origin(self, **kwargs)

def unlink_fast(self, **kwargs):
self = self.with_context(auditlog_disabled=True)
self = self.with_context(auditlog_disabled_read=True)
rule_model = self.env["auditlog.rule"]
if self.env.user in users_to_exclude:
return unlink_fast.origin(self, **kwargs)
Expand All @@ -583,7 +588,7 @@ def _make_export_data(self):

def export_data(self, fields_to_export):
res = export_data.origin(self, fields_to_export)
self = self.with_context(auditlog_disabled=True)
self = self.with_context(auditlog_disabled_read=True)
rule_model = self.env["auditlog.rule"]
if self.env.user in users_to_exclude:
return res
Expand Down
3 changes: 3 additions & 0 deletions auditlog/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@
- Bogdan Valentin Gabor \<<valentin.gabor@bt-group.com>\>
- Dennis Sluijk <d.sluijk@onestein.nl>
- Adam Heinz \<<adam.heinz@metricwise.com>\>
- [OERP Canada](https://www.oerp.ca/):

- Hembert Iregui \<<hi@oerp.ca\>
4 changes: 4 additions & 0 deletions auditlog/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,10 @@ <h3><a class="toc-backref" href="#toc-entry-6">Contributors</a></h3>
<li>Bogdan Valentin Gabor &lt;<a class="reference external" href="mailto:valentin.gabor&#64;bt-group.com">valentin.gabor&#64;bt-group.com</a>&gt;</li>
<li>Dennis Sluijk <a class="reference external" href="mailto:d.sluijk&#64;onestein.nl">d.sluijk&#64;onestein.nl</a></li>
<li>Adam Heinz &lt;<a class="reference external" href="mailto:adam.heinz&#64;metricwise.com">adam.heinz&#64;metricwise.com</a>&gt;</li>
<li><a class="reference external" href="https://www.oerp.ca/">OERP Canada</a>:<ul>
<li>Hembert Iregui &lt;&lt;<a class="reference external" href="mailto:hi&#64;oerp.ca">hi&#64;oerp.ca</a>&gt;</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="other-credits">
Expand Down
1 change: 1 addition & 0 deletions test_auditlog/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import test_account_bank_statement_line
from . import test_account_move_reverse
from . import test_product_tax_multicompany
from . import test_account_reentrancy
56 changes: 56 additions & 0 deletions test_auditlog/tests/test_account_reentrancy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from odoo.tests.common import tagged

from odoo.addons.auditlog.tests.common import AuditLogRuleCommon


@tagged("post_install", "-at_install")
class TestAccountAuditlog(AuditLogRuleCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.account_model_id = cls.env.ref("account.model_account_account").id
cls.rule = cls.create_rule(
{
"name": "Account Audit Rule",
"model_id": cls.account_model_id,
"log_create": True,
"log_write": True,
"log_read": True,
"log_unlink": True,
"log_type": "full",
}
)
cls.rule.set_to_confirmed()

def test_write_code_reentrancy(self):
Comment thread
hi-oerp marked this conversation as resolved.
"""This test verifies the infinite recursion scenario
that occurs when a field defines both _compute_code and _inverse_code.
It ensures that the introduced guard correctly prevents re-entering
the same field's compute/inverse cycle, avoiding recursive execution
while preserving the expected field behavior.
"""
account = self.env["account.account"].create(
{
"name": "Test Account",
"code": "1000",
}
)
logs = self.env["auditlog.log"].search(
[
("model_id", "=", self.account_model_id),
("method", "=", "write"),
("res_id", "=", account.id),
]
)
self.assertTrue(
logs.line_ids.filtered(lambda log_line: log_line.field_name == "code_store")
)
account.write({"code": "2000"})
logs = self.env["auditlog.log"].search(
[
("model_id", "=", self.account_model_id),
("method", "=", "write"),
("res_id", "=", account.id),
]
)
self.assertEqual(len(logs), 2)
Loading