From fbe55979af8aaf184b7e3fb4932945f0232c1e8b Mon Sep 17 00:00:00 2001 From: Felix Coca Date: Fri, 7 Nov 2025 15:13:26 -0400 Subject: [PATCH 1/7] [FEAT] Add bulk subscribe actions for auditlog rules - add server actions to trigger subscribe/unsubscribe from list view - ensure return type suits server action flow - support bulk handling without interfering with form buttons --- auditlog/__manifest__.py | 1 + auditlog/models/rule.py | 9 +++++++++ auditlog/views/auditlog_rule_actions.xml | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 auditlog/views/auditlog_rule_actions.xml diff --git a/auditlog/__manifest__.py b/auditlog/__manifest__.py index b5d9a8bc86f..053c59be9bd 100644 --- a/auditlog/__manifest__.py +++ b/auditlog/__manifest__.py @@ -14,6 +14,7 @@ "security/ir.model.access.csv", "data/ir_cron.xml", "views/auditlog_view.xml", + "views/auditlog_rule_actions.xml", "views/http_session_view.xml", "views/http_request_view.xml", ], diff --git a/auditlog/models/rule.py b/auditlog/models/rule.py index 2cdb4ae8d2d..f65239678da 100644 --- a/auditlog/models/rule.py +++ b/auditlog/models/rule.py @@ -794,6 +794,15 @@ def unsubscribe(self): act_window.unlink() return self.write({"state": "draft"}) + def action_server_bulk_subscribe(self): + """Bulk subscribe rules""" + self.subscribe() + return {"type": "ir.actions.client", "tag": "soft_reload"} + + def action_server_bulk_unsubscribe(self): + self.unsubscribe() + return {"type": "ir.actions.client", "tag": "soft_reload"} + @api.model def _update_vals_list(self, vals_list): # Odoo supports empty recordset assignment (while it doesn't handle diff --git a/auditlog/views/auditlog_rule_actions.xml b/auditlog/views/auditlog_rule_actions.xml new file mode 100644 index 00000000000..fb010410e35 --- /dev/null +++ b/auditlog/views/auditlog_rule_actions.xml @@ -0,0 +1,20 @@ + + + + Subscribe Rules + + + action + code + action = records.action_server_bulk_subscribe() + + + + Unsubscribe Rules + + + action + code + action = records.action_server_bulk_unsubscribe() + + \ No newline at end of file From 5bd23cebc266ef69883d11806784f70bdd40686c Mon Sep 17 00:00:00 2001 From: Felix Coca Date: Fri, 7 Nov 2025 15:17:16 -0400 Subject: [PATCH 2/7] Update README and HTML documentation for Audit Log - Removed the Odoo Community banner image from README. - Corrected spelling of "license" to "licence" in badge link. - Updated HTML title to "Audit Log" for better clarity. - Changed section headings from

to

for improved structure in HTML documentation. - Ensured proper formatting and consistency across documentation files. --- auditlog/README.rst | 6 +---- auditlog/static/description/index.html | 30 ++++++++++-------------- auditlog/views/auditlog_rule_actions.xml | 4 ++-- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/auditlog/README.rst b/auditlog/README.rst index 6c603514dce..b583c0a7ac0 100644 --- a/auditlog/README.rst +++ b/auditlog/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ========= Audit Log ========= @@ -17,7 +13,7 @@ Audit Log .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github diff --git a/auditlog/static/description/index.html b/auditlog/static/description/index.html index 0859b2884b1..a30df380364 100644 --- a/auditlog/static/description/index.html +++ b/auditlog/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Audit Log -
+
+

Audit Log

- - -Odoo Community Association - -
-

Audit Log

-

Beta License: AGPL-3 OCA/server-tools Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/server-tools Translate me on Weblate Try me on Runboat

This module allows the administrator to log user operations performed on data models such as create, read, write and delete.

Table of contents

@@ -393,7 +388,7 @@

Audit Log

-

Usage

+

Usage

Go to Settings / Technical / Audit / Rules to subscribe rules. A rule defines which operations to log for a given data model.

image

@@ -417,7 +412,7 @@

Usage

right to configure the auditlog configuration rules.

-

Known issues / Roadmap

+

Known issues / Roadmap

  • log only operations triggered by some users (currently it logs all @@ -428,7 +423,7 @@

    Known issues / Roadmap

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -436,15 +431,15 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • ABF OSIELL
-

Contributors

+

Contributors

-

Other credits

+

Other credits

  • Icon: built with different icons from the Oxygen theme (LGPL)
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -481,6 +476,5 @@

Maintainers

-
diff --git a/auditlog/views/auditlog_rule_actions.xml b/auditlog/views/auditlog_rule_actions.xml index fb010410e35..2f9dc433d07 100644 --- a/auditlog/views/auditlog_rule_actions.xml +++ b/auditlog/views/auditlog_rule_actions.xml @@ -1,4 +1,4 @@ - + Subscribe Rules @@ -17,4 +17,4 @@ code action = records.action_server_bulk_unsubscribe() - \ No newline at end of file + From 1e0462b0ed2dbaa940ceba649863a3b601c025dc Mon Sep 17 00:00:00 2001 From: Felix Coca Date: Fri, 7 Nov 2025 15:48:20 -0400 Subject: [PATCH 3/7] [TEST] Add bulk actions tests for audit log rules - Introduced a new test class for bulk subscribe and unsubscribe actions. - Implemented tests to verify the correct behavior of bulk subscription and unsubscription for audit log rules. - Ensured that the state of rules is correctly updated after bulk actions. --- auditlog/tests/test_auditlog.py | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/auditlog/tests/test_auditlog.py b/auditlog/tests/test_auditlog.py index a8df47d5f6f..88f9179d973 100644 --- a/auditlog/tests/test_auditlog.py +++ b/auditlog/tests/test_auditlog.py @@ -746,3 +746,66 @@ def test_01_AuditlogFast_field_exclude_write_log(self): ] ) ) + + +class AuditLogRuleBulkActions(AuditLogRuleCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.rule_country = cls.create_rule( + { + "name": "Country bulk rule", + "model_id": cls.env.ref("base.model_res_country").id, + "log_read": False, + "log_create": True, + "log_write": True, + "log_unlink": True, + "log_type": "fast", + } + ) + cls.rule_state = cls.create_rule( + { + "name": "State bulk rule", + "model_id": cls.env.ref("base.model_res_country_state").id, + "log_read": False, + "log_create": True, + "log_write": True, + "log_unlink": True, + "log_type": "fast", + } + ) + cls.rules = cls.rule_country | cls.rule_state + + def test_01_bulk_subscribe(self): + self.rules.action_server_bulk_unsubscribe() + + action_result = self.rules.action_server_bulk_subscribe() + + self.assertEqual( + action_result, {"type": "ir.actions.client", "tag": "soft_reload"} + ) + self.rules.invalidate_recordset() + self.assertTrue(all(rule.state == "subscribed" for rule in self.rules)) + for rule in self.rules: + self.assertTrue(rule.action_id) + self.assertEqual(rule.action_id.binding_model_id, rule.model_id) + + def test_02_bulk_unsubscribe(self): + self.rules.action_server_bulk_unsubscribe() + self.rules.action_server_bulk_subscribe() + self.rules.invalidate_recordset() + action_ids = self.rules.mapped("action_id.id") + self.assertTrue(action_ids) + + action_result = self.rules.action_server_bulk_unsubscribe() + + self.assertEqual( + action_result, {"type": "ir.actions.client", "tag": "soft_reload"} + ) + self.rules.invalidate_recordset() + self.assertTrue(all(rule.state == "draft" for rule in self.rules)) + self.assertFalse(any(self.rules.mapped("action_id"))) + remaining_actions = self.env["ir.actions.act_window"].search( + [("id", "in", action_ids)] + ) + self.assertFalse(remaining_actions) From f7e6e53d909f5495c328541bbec8b08f4fc11f76 Mon Sep 17 00:00:00 2001 From: Drkpkg Date: Sun, 9 Nov 2025 00:57:33 -0400 Subject: [PATCH 4/7] [FIX] Improve bulk subscribe/unsubscribe actions in auditlog rules - Updated the bulk subscribe method to only subscribe rules that are not already subscribed. - Modified the bulk unsubscribe method to only unsubscribe rules that are currently subscribed. - Changed return values to True for better integration with server action flow. --- auditlog/models/rule.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/auditlog/models/rule.py b/auditlog/models/rule.py index f65239678da..8042446471b 100644 --- a/auditlog/models/rule.py +++ b/auditlog/models/rule.py @@ -796,12 +796,12 @@ def unsubscribe(self): def action_server_bulk_subscribe(self): """Bulk subscribe rules""" - self.subscribe() - return {"type": "ir.actions.client", "tag": "soft_reload"} + self.filtered(lambda rule: rule.state != "subscribed").subscribe() + return True def action_server_bulk_unsubscribe(self): - self.unsubscribe() - return {"type": "ir.actions.client", "tag": "soft_reload"} + self.filtered(lambda rule: rule.state == "subscribed").unsubscribe() + return True @api.model def _update_vals_list(self, vals_list): From ffebae1cfff7fb13b0c0e2eb07053f884a99b397 Mon Sep 17 00:00:00 2001 From: Drkpkg Date: Sun, 9 Nov 2025 02:19:13 -0400 Subject: [PATCH 5/7] [TEST] Enhance bulk actions tests for audit log rules - Added cleanup logic in setUpClass to remove existing rules before creating new ones. - Implemented tearDownClass to ensure proper unsubscription and deletion of rules after tests. - Improved test setup for bulk subscribe/unsubscribe actions to maintain a clean state. --- auditlog/tests/test_auditlog.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/auditlog/tests/test_auditlog.py b/auditlog/tests/test_auditlog.py index 88f9179d973..9496cf9d29e 100644 --- a/auditlog/tests/test_auditlog.py +++ b/auditlog/tests/test_auditlog.py @@ -752,10 +752,20 @@ class AuditLogRuleBulkActions(AuditLogRuleCommon): @classmethod def setUpClass(cls): super().setUpClass() + country_model = cls.env.ref("base.model_res_country") + state_model = cls.env.ref("base.model_res_country_state") + + existing_rules = cls.env["auditlog.rule"].search( + [("model_id", "in", (country_model.id, state_model.id))] + ) + if existing_rules: + existing_rules.action_server_bulk_unsubscribe() + existing_rules.unlink() + cls.rule_country = cls.create_rule( { "name": "Country bulk rule", - "model_id": cls.env.ref("base.model_res_country").id, + "model_id": country_model.id, "log_read": False, "log_create": True, "log_write": True, @@ -766,7 +776,7 @@ def setUpClass(cls): cls.rule_state = cls.create_rule( { "name": "State bulk rule", - "model_id": cls.env.ref("base.model_res_country_state").id, + "model_id": state_model.id, "log_read": False, "log_create": True, "log_write": True, @@ -776,6 +786,13 @@ def setUpClass(cls): ) cls.rules = cls.rule_country | cls.rule_state + @classmethod + def tearDownClass(cls): + if cls.rules: + cls.rules.action_server_bulk_unsubscribe() + cls.rules.unlink() + super().tearDownClass() + def test_01_bulk_subscribe(self): self.rules.action_server_bulk_unsubscribe() From 12bf5aac7a308f81bab5b3fa90a2af12d2355459 Mon Sep 17 00:00:00 2001 From: Drkpkg Date: Sun, 9 Nov 2025 13:02:37 -0400 Subject: [PATCH 6/7] [TEST] Update assertions in bulk actions tests for audit log rules - Changed assertions in bulk subscribe and unsubscribe tests to check for truthy return values instead of specific action results. - Ensured that the state of rules is validated after performing bulk actions, maintaining consistency in test outcomes. --- auditlog/tests/test_auditlog.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/auditlog/tests/test_auditlog.py b/auditlog/tests/test_auditlog.py index 9496cf9d29e..75d43fc184b 100644 --- a/auditlog/tests/test_auditlog.py +++ b/auditlog/tests/test_auditlog.py @@ -798,9 +798,7 @@ def test_01_bulk_subscribe(self): action_result = self.rules.action_server_bulk_subscribe() - self.assertEqual( - action_result, {"type": "ir.actions.client", "tag": "soft_reload"} - ) + self.assertTrue(action_result) self.rules.invalidate_recordset() self.assertTrue(all(rule.state == "subscribed" for rule in self.rules)) for rule in self.rules: @@ -816,9 +814,7 @@ def test_02_bulk_unsubscribe(self): action_result = self.rules.action_server_bulk_unsubscribe() - self.assertEqual( - action_result, {"type": "ir.actions.client", "tag": "soft_reload"} - ) + self.assertTrue(action_result) self.rules.invalidate_recordset() self.assertTrue(all(rule.state == "draft" for rule in self.rules)) self.assertFalse(any(self.rules.mapped("action_id"))) From b297b348db3024a654a6d8e7eca966ee25dcc29f Mon Sep 17 00:00:00 2001 From: Drkpkg Date: Sun, 9 Nov 2025 13:11:04 -0400 Subject: [PATCH 7/7] [TEST] Simplify existing rules cleanup in bulk actions tests - Removed conditional check for existing rules before unsubscribing and unlinking. - Ensured that cleanup actions are always executed to maintain test integrity. --- auditlog/tests/test_auditlog.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/auditlog/tests/test_auditlog.py b/auditlog/tests/test_auditlog.py index 75d43fc184b..58731360b8d 100644 --- a/auditlog/tests/test_auditlog.py +++ b/auditlog/tests/test_auditlog.py @@ -758,9 +758,8 @@ def setUpClass(cls): existing_rules = cls.env["auditlog.rule"].search( [("model_id", "in", (country_model.id, state_model.id))] ) - if existing_rules: - existing_rules.action_server_bulk_unsubscribe() - existing_rules.unlink() + existing_rules.action_server_bulk_unsubscribe() + existing_rules.unlink() cls.rule_country = cls.create_rule( {