From aa3a90a7b429fb001ca5cd5fa5425d750d780639 Mon Sep 17 00:00:00 2001 From: tarteo Date: Tue, 28 Nov 2023 14:27:21 +0100 Subject: [PATCH] [12.0] auditlog: Log exports --- auditlog/README.rst | 1 + auditlog/models/log.py | 11 ++++ auditlog/models/rule.py | 71 ++++++++++++++++++++------ auditlog/readme/CONTRIBUTORS.rst | 1 + auditlog/static/description/index.html | 2 + auditlog/tests/test_auditlog.py | 17 ++++++ auditlog/views/auditlog_view.xml | 23 ++++++++- 7 files changed, 109 insertions(+), 17 deletions(-) diff --git a/auditlog/README.rst b/auditlog/README.rst index 843475660ef..7c2d60c340f 100644 --- a/auditlog/README.rst +++ b/auditlog/README.rst @@ -115,6 +115,7 @@ Contributors * Holden Rehg * Bhavesh Odedra * Hardik Suthar +* Dennis Sluijk Other credits ~~~~~~~~~~~~~ diff --git a/auditlog/models/log.py b/auditlog/models/log.py index bbab1fc9211..0407169bfec 100644 --- a/auditlog/models/log.py +++ b/auditlog/models/log.py @@ -1,6 +1,7 @@ # Copyright 2015 ABF OSIELL # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import models, fields +from odoo.tools.safe_eval import safe_eval class AuditlogLog(models.Model): @@ -12,6 +13,7 @@ class AuditlogLog(models.Model): model_id = fields.Many2one( 'ir.model', string="Model") res_id = fields.Integer("Resource ID") + res_ids = fields.Char("Resource IDs") user_id = fields.Many2one( 'res.users', string="User") method = fields.Char("Method", size=64) @@ -27,6 +29,15 @@ class AuditlogLog(models.Model): ], string="Type") + def show_res_ids(self): + self.ensure_one() + return { + "type": "ir.actions.act_window", + "view_mode": "tree,form", + "res_model": self.model_id.model, + "domain": [("id", "in", safe_eval(self.res_ids))], + } + class AuditlogLogLine(models.Model): _name = 'auditlog.log.line' diff --git a/auditlog/models/rule.py b/auditlog/models/rule.py index 88cd08f4699..1b26bf94273 100644 --- a/auditlog/models/rule.py +++ b/auditlog/models/rule.py @@ -82,6 +82,15 @@ class AuditlogRule(models.Model): help=("Select this if you want to keep track of creation on any " "record of the model of this rule"), states={'subscribed': [('readonly', True)]}) + log_export_data = fields.Boolean( + "Log Exports", + default=True, + help=( + "Select this if you want to keep track of exports " + "of the model of this rule" + ), + states={"subscribed": [("readonly", True)]}, + ) log_type = fields.Selection( [('full', "Full log"), ('fast', "Fast log"), @@ -179,6 +188,12 @@ def _patch_methods(self): model_model._patch_method('unlink', rule._make_unlink()) setattr(type(model_model), check_attr, True) updated = True + # -> export_data + check_attr = 'auditlog_ruled_export_data' + if rule.log_export_data and not hasattr(model_model, check_attr): + model_model._patch_method('export_data', rule._make_export_data()) + setattr(type(model_model), check_attr, True) + updated = True return updated @api.multi @@ -187,7 +202,7 @@ def _revert_methods(self): updated = False for rule in self: model_model = self.env[rule.model_id.model] - for method in ['create', 'read', 'write', 'unlink']: + for method in ['create', 'read', 'write', 'unlink', 'export_data']: if getattr(rule, 'log_%s' % method) and hasattr( getattr(model_model, method), 'origin'): model_model._revert_method(method) @@ -231,6 +246,28 @@ def get_auditlog_fields(self, model): if (not f.compute and not f.related) or f.store ) + def _make_export_data(self): + """Instanciate a export method that log its calls.""" + self.ensure_one() + log_type = self.log_type + + def export_data(self, fields_to_export, raw_data=False): + res = export_data.origin(self, fields_to_export, raw_data) + self = self.with_context(auditlog_disabled=True) + rule_model = self.env["auditlog.rule"] + rule_model.sudo().create_logs( + self.env.uid, + self._name, + self.ids, + "export_data", + None, + None, + {"log_type": log_type}, + ) + return res + + return export_data + @api.multi def _make_create(self): """Instanciate a create method that log its calls.""" @@ -393,24 +430,26 @@ def create_logs(self, uid, res_model, res_ids, method, log_model = self.env['auditlog.log'] http_request_model = self.env['auditlog.http.request'] http_session_model = self.env['auditlog.http.session'] + model_model = self.env[res_model] + model_id = self.pool._auditlog_model_cache[res_model] + auditlog_rule = self.env['auditlog.rule'].search([('model_id', '=', model_id)]) + vals = { + 'model_id': model_id, + 'method': method, + 'user_id': uid, + 'http_request_id': http_request_model.current_http_request(), + 'http_session_id': http_session_model.current_http_session(), + } + vals.update(additional_log_values or {}) + if method == 'export_data': + vals.update({'name': res_model, 'res_ids': str(res_ids)}) + return log_model.create(vals) + for res_id in res_ids: - model_model = self.env[res_model] name = model_model.browse(res_id).name_get() - model_id = self.pool._auditlog_model_cache[res_model] - auditlog_rule = self.env['auditlog.rule'].search( - [("model_id", "=", model_id)]) res_name = name and name[0] and name[0][1] - vals = { - 'name': res_name, - 'model_id': self.pool._auditlog_model_cache[res_model], - 'res_id': res_id, - 'method': method, - 'user_id': uid, - 'http_request_id': http_request_model.current_http_request(), - 'http_session_id': http_session_model.current_http_session(), - } - vals.update(additional_log_values or {}) - log = log_model.create(vals) + log_vals = {**vals, 'name': res_name, 'res_id': res_id} + log = log_model.create(log_vals) diff = DictDiffer( new_values.get(res_id, EMPTY_DICT), old_values.get(res_id, EMPTY_DICT)) diff --git a/auditlog/readme/CONTRIBUTORS.rst b/auditlog/readme/CONTRIBUTORS.rst index 9e70c02fb84..84ace92ff17 100644 --- a/auditlog/readme/CONTRIBUTORS.rst +++ b/auditlog/readme/CONTRIBUTORS.rst @@ -3,3 +3,4 @@ * Holden Rehg * Bhavesh Odedra * Hardik Suthar +* Dennis Sluijk diff --git a/auditlog/static/description/index.html b/auditlog/static/description/index.html index cac22a7da9d..4a25c0f5622 100644 --- a/auditlog/static/description/index.html +++ b/auditlog/static/description/index.html @@ -1,3 +1,4 @@ + @@ -460,6 +461,7 @@

Contributors

  • Holden Rehg <holdenrehg@gmail.com>
  • Bhavesh Odedra <bodedra@opensourceintegrators.com>
  • Hardik Suthar <hsuthar@opensourceintegrators.com>
  • +
  • Dennis Sluijk <d.sluijk@onestein.nl>
  • diff --git a/auditlog/tests/test_auditlog.py b/auditlog/tests/test_auditlog.py index d833d108cb9..8d0ff77c408 100644 --- a/auditlog/tests/test_auditlog.py +++ b/auditlog/tests/test_auditlog.py @@ -181,6 +181,23 @@ def test_LogDuringUpdate(self): ])) sql.rename_column(self.env.cr, Rule._table, temp_name, field_name) + def test_LogExport(self): + self.groups_rule.subscribe() + + auditlog_log = self.env["auditlog.log"] + self.env["res.groups"].search([]).export_data(["name"]) + created_log = auditlog_log.search( + [ + ("model_id", "=", self.groups_model_id), + ("method", "=", "export_data"), + ] + ).ensure_one() + self.assertTrue(created_log) + action = created_log.show_res_ids() + domain = action["domain"] # [('id', 'in', [1, 2, ...])] + self.assertIsInstance(domain, list) + self.assertIsInstance(domain[0][2], list) + class TestAuditlogFull(TransactionCase, AuditlogCommon): diff --git a/auditlog/views/auditlog_view.xml b/auditlog/views/auditlog_view.xml index 520e4f7991a..66fd1a011e6 100644 --- a/auditlog/views/auditlog_view.xml +++ b/auditlog/views/auditlog_view.xml @@ -33,6 +33,7 @@ + @@ -52,6 +53,7 @@ + @@ -97,6 +99,16 @@
    +
    +
    @@ -106,7 +118,16 @@ - + +