From fe00f4c31928e22875f36f2f9998df49c2c7fa43 Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Capalbo Date: Mon, 11 Apr 2022 11:36:15 +0200 Subject: [PATCH 1/2] [ADD] pre-review version --- auditlog/:w | 13 ++ auditlog/models/rule.py | 2 + auditlog/views/auditlog_view.xml | 2 +- auditlog_security/README.rst | 112 +++++++++++++++++ auditlog_security/__init__.py | 3 + auditlog_security/__manifest__.py | 21 ++++ auditlog_security/demo/auditlog_rule.xml | 10 ++ auditlog_security/models/__init__.py | 5 + .../models/auditlog_autovacuum.py | 14 +++ auditlog_security/models/auditlog_rule.py | 71 +++++++++++ auditlog_security/models/ir_rule.py | 52 ++++++++ auditlog_security/readme/CONTRIBUTORS.rst | 1 + auditlog_security/readme/CREDITS.rst | 0 auditlog_security/readme/DESCRIPTION.rst | 3 + auditlog_security/readme/ROADMAP.rst | 1 + auditlog_security/readme/USAGE.rst | 10 ++ .../security/ir.model.access.csv | 3 + auditlog_security/views/auditlog_view.xml | 114 ++++++++++++++++++ 18 files changed, 436 insertions(+), 1 deletion(-) create mode 100644 auditlog/:w create mode 100644 auditlog_security/README.rst create mode 100644 auditlog_security/__init__.py create mode 100644 auditlog_security/__manifest__.py create mode 100644 auditlog_security/demo/auditlog_rule.xml create mode 100644 auditlog_security/models/__init__.py create mode 100644 auditlog_security/models/auditlog_autovacuum.py create mode 100644 auditlog_security/models/auditlog_rule.py create mode 100644 auditlog_security/models/ir_rule.py create mode 100644 auditlog_security/readme/CONTRIBUTORS.rst create mode 100644 auditlog_security/readme/CREDITS.rst create mode 100644 auditlog_security/readme/DESCRIPTION.rst create mode 100644 auditlog_security/readme/ROADMAP.rst create mode 100644 auditlog_security/readme/USAGE.rst create mode 100644 auditlog_security/security/ir.model.access.csv create mode 100644 auditlog_security/views/auditlog_view.xml diff --git a/auditlog/:w b/auditlog/:w new file mode 100644 index 00000000000..8b489702eb1 --- /dev/null +++ b/auditlog/:w @@ -0,0 +1,13 @@ +# Copyright 2021 Therp B.V. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models, api + + +class AuditlogAutovacuum(models.TransientModel): + _inherit = 'auditlog.autovacuum' + + @api.model + def autovaccum(self, days): + return super(AuditlogAutovacuum, self.with_context( + auditlog_write=True)).autovacuum(days=days) diff --git a/auditlog/models/rule.py b/auditlog/models/rule.py index 6cdc7233ccd..e7a3c8f6492 100644 --- a/auditlog/models/rule.py +++ b/auditlog/models/rule.py @@ -449,6 +449,8 @@ def _create_log_line_on_write( self, log, fields_list, old_values, new_values): """Log field updated on a 'write' operation.""" log_line_model = self.env['auditlog.log.line'] + import pudb + pudb.set_trace() for field_name in fields_list: if field_name in FIELDS_BLACKLIST: continue diff --git a/auditlog/views/auditlog_view.xml b/auditlog/views/auditlog_view.xml index 2ec7b480896..8eaefc4e36a 100644 --- a/auditlog/views/auditlog_view.xml +++ b/auditlog/views/auditlog_view.xml @@ -193,7 +193,7 @@ Logs auditlog.log form - + `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ABF OSIELL + +Contributors +~~~~~~~~~~~~ + +* Sebastien Alix +* Holger Brunn +* Holden Rehg + +Other credits +~~~~~~~~~~~~~ + +* Icon: built with different icons from the `Oxygen theme `_ (LGPL) + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/server-tools `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/auditlog_security/__init__.py b/auditlog_security/__init__.py new file mode 100644 index 00000000000..31660d6a965 --- /dev/null +++ b/auditlog_security/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models diff --git a/auditlog_security/__manifest__.py b/auditlog_security/__manifest__.py new file mode 100644 index 00000000000..5e196c31fa3 --- /dev/null +++ b/auditlog_security/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2021 Therp B.V. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Audit Log Permissions", + "version": "11.0.1.0.1", + "author": "Therp B.V.,Odoo Community Association (OCA)", + "license": "AGPL-3", + "website": "https://github.com/OCA/server-tools/", + "category": "Tools", + "depends": [ + "auditlog", + "contacts", + ], + "data": [ + "demo/auditlog_rule.xml", + "views/auditlog_view.xml", + ], + "application": True, + "installable": True, +} diff --git a/auditlog_security/demo/auditlog_rule.xml b/auditlog_security/demo/auditlog_rule.xml new file mode 100644 index 00000000000..eb7639adc6e --- /dev/null +++ b/auditlog_security/demo/auditlog_rule.xml @@ -0,0 +1,10 @@ + + + + + main auditlog partner rule + + subscribed + + + diff --git a/auditlog_security/models/__init__.py b/auditlog_security/models/__init__.py new file mode 100644 index 00000000000..aa60319d2a3 --- /dev/null +++ b/auditlog_security/models/__init__.py @@ -0,0 +1,5 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import auditlog_rule +from . import ir_rule +from . import auditlog_autovacuum diff --git a/auditlog_security/models/auditlog_autovacuum.py b/auditlog_security/models/auditlog_autovacuum.py new file mode 100644 index 00000000000..c37db710aaf --- /dev/null +++ b/auditlog_security/models/auditlog_autovacuum.py @@ -0,0 +1,14 @@ +# Copyright 2021 Therp B.V. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models, api + + +class AuditlogAutovacuum(models.TransientModel): + _inherit = "auditlog.autovacuum" + + @api.model + def autovaccum(self, days): + return super( + AuditlogAutovacuum, self.with_context(auditlog_write=True) + ).autovacuum(days=days) diff --git a/auditlog_security/models/auditlog_rule.py b/auditlog_security/models/auditlog_rule.py new file mode 100644 index 00000000000..fd45558ca70 --- /dev/null +++ b/auditlog_security/models/auditlog_rule.py @@ -0,0 +1,71 @@ +# Copyright 2021 Therp B.V. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models, fields, api, modules, _ +from odoo.addons.auditlog.models.rule import FIELDS_BLACKLIST + + +class AuditlogRule(models.Model): + _inherit = "auditlog.rule" + + field_ids = fields.Many2many( + "ir.model.fields", + required=True, + ) + group_ids = fields.Many2many( + "res.groups", + string="Groups", + help="""Groups that will be allowed to see the logged fields, if left empty + all groups will be allowed (global rule creation)""", + ) + + """ note this solution will work only with a hardcoded design of models, + because on initialization , self.model_id.id still is not defined. + for now, to keep generality we put the filtering in the view.""" + + def get_field_ids_domain(self): + return [ + ("model_id", "=", self.env.ref("base.model_res_partner").id), + ("name", "not in", FIELDS_BLACKLIST), + ] + + def unlink(self): + # if we delete auditlog rule, corresponding ir.rules are removed + # TODO PROPOSAL: a warning here with detailed information? + res = super(AuditlogRule, self).unlink() + return ( + res + and self.env["ir.rule"] + .with_context(auditlog_write=True) + .search([("auditlog_id", "in", self.ids)]) + .unlink() + ) + + @api.multi + def write(self, vals): + res = super(AuditlogRule, self).write(vals) + for this in self: + if any([x in vals for x in ("group_ids", "field_ids", "model_id")]): + this.generate_rules() + return res + + def generate_rules(self): + old_rule = self.env["ir.rule"].search([("auditlog_id", "=", self.id)], limit=1) + domain_force = ( + "[ " + + " ('log_id.model_id' , '=', %s)," % (self.model_id.id) + + "('field_id', 'in', %s)" % (self.field_ids.ids) + + "]" + ) + values = { + "name": "auditlog_extended_%s" % self.id, + "model_id": self.env.ref("auditlog.model_auditlog_log_line").id, + "groups": [(6, 0, self.group_ids.ids)], + "perm_read": True, + "domain_force": domain_force, + "auditlog_id": self.id, + } + if old_rule: + old_rule.with_context(auditlog_write=True).write(values) + else: + self.with_context(auditlog_write=True).env["ir.rule"].create(values) diff --git a/auditlog_security/models/ir_rule.py b/auditlog_security/models/ir_rule.py new file mode 100644 index 00000000000..44176e14afe --- /dev/null +++ b/auditlog_security/models/ir_rule.py @@ -0,0 +1,52 @@ +# Copyright 2021 Therp B.V. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import exceptions, models, fields, api, _ + + +class IrRule(models.Model): + _inherit = "ir.rule" + + auditlog_id = fields.Many2one( + "auditlog.rule", + required=False, + help="Auditlog Rule that generated this ir.rule", + ) + + def prevent_rule_mod(self, vals=None): + auditlog_write = self.env.context.get("auditlog_write") + if "auditlog_id" in vals and not auditlog_write: + raise exceptions.validationerror(_("""Cannot change auditlog_id""")) + for this in self: + if this.auditlog_id and not auditlog_write: + raise exceptions.validationerror( + _( + """ + auditlog line rules are automatically generated from the auditlog + interface, please use that to edit/delete/""" + ) + ) + + @api.model + def create(self, values): + if values.get("model_id") == self.env.ref( + "auditlog.model_auditlog_log_line" + ).id and not self.env.context.get("auditlog_write"): + raise exceptions.ValidationError( + _( + """ + Auditlog line rules are automatically generated from the auditlog + interface, please use that to create""" + ) + ) + return super(IrRule, self).create(values) + + @api.multi + def write(self, vals): + self.prevent_rule_mod(vals) + return super(IrRule, self).write(vals) + + @api.multi + def unlink(self): + self.prevent_rule_mod() + return super(IrRule, self).unlink() diff --git a/auditlog_security/readme/CONTRIBUTORS.rst b/auditlog_security/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..addcc3f4a2b --- /dev/null +++ b/auditlog_security/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Giovanni Francesco Capalbo diff --git a/auditlog_security/readme/CREDITS.rst b/auditlog_security/readme/CREDITS.rst new file mode 100644 index 00000000000..e69de29bb2d diff --git a/auditlog_security/readme/DESCRIPTION.rst b/auditlog_security/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..2d056774e16 --- /dev/null +++ b/auditlog_security/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module allows extends auditlog, allowing specific log lines to be viewed only +by users belonging to specific views, while all other lines are allowed only to +administrator. diff --git a/auditlog_security/readme/ROADMAP.rst b/auditlog_security/readme/ROADMAP.rst new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/auditlog_security/readme/ROADMAP.rst @@ -0,0 +1 @@ + diff --git a/auditlog_security/readme/USAGE.rst b/auditlog_security/readme/USAGE.rst new file mode 100644 index 00000000000..8fa4cd27178 --- /dev/null +++ b/auditlog_security/readme/USAGE.rst @@ -0,0 +1,10 @@ +Go to `Settings / Technical / Audit / Rules` to subscribe rules. A rule defines +which operations to log for a given data model. +The rule is now extended with a new field permission_ids, that tells us wich groups will +be allowed to read the lines produced by this rule. +If permission_ids is left empty, the default will be: +"auditlog lines visible only by administrator" + + +Then, check logs in the `Settings / Technical / Audit / Logs` menu. You can +group them by user sessions, date, data model , HTTP requests. diff --git a/auditlog_security/security/ir.model.access.csv b/auditlog_security/security/ir.model.access.csv new file mode 100644 index 00000000000..005a168ba9d --- /dev/null +++ b/auditlog_security/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_auditlog_log_line_user,auditlog_log_line_user,model_auditlog_log_line,base.group_user,1,0,0,0 +access_auditlog_log_user,auditlog_log_user,model_auditlog_log,base.group_user,1,0,0,0 diff --git a/auditlog_security/views/auditlog_view.xml b/auditlog_security/views/auditlog_view.xml new file mode 100644 index 00000000000..46df0263ce9 --- /dev/null +++ b/auditlog_security/views/auditlog_view.xml @@ -0,0 +1,114 @@ + + + + + auditlog.log.line.form + auditlog.log.line + +
+ + + + + + + + + +
+
+
+ + + + auditlog.log.line.tree + auditlog.log.line + + + + + + + + + + + + + + + + + auditlog rule form extension + auditlog.rule + + + + + + + + + + + + + + + + + + auditlog rule tree extension + auditlog.rule + + + + + + + + + + + auditlog.log.search + auditlog.log.line + + + + + + + + + + + + Logs + auditlog.log.line + form + + [('log_id.res_id', '=', active_id)] + + + + + + +
From aded99e3732c01b91f31f75ecdc37398140aa0d8 Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Capalbo Date: Wed, 13 Apr 2022 11:45:14 +0200 Subject: [PATCH 2/2] [ADD] review fixes --- auditlog/:w | 13 - auditlog/models/rule.py | 2 - auditlog/views/auditlog_view.xml | 2 +- auditlog_security/README.rst | 55 +-- auditlog_security/__manifest__.py | 8 +- auditlog_security/demo/auditlog_rule.xml | 10 - auditlog_security/models/__init__.py | 1 + .../models/auditlog_autovacuum.py | 2 +- .../models/auditlog_line_access_rule.py | 115 +++++ auditlog_security/models/auditlog_rule.py | 85 ++-- auditlog_security/models/ir_rule.py | 42 +- auditlog_security/readme/USAGE.rst | 3 +- .../security/ir.model.access.csv | 1 + .../static/description/index.html | 438 ++++++++++++++++++ auditlog_security/views/auditlog_view.xml | 106 +++-- maintainer-tools | 1 + 16 files changed, 691 insertions(+), 193 deletions(-) delete mode 100644 auditlog/:w delete mode 100644 auditlog_security/demo/auditlog_rule.xml create mode 100644 auditlog_security/models/auditlog_line_access_rule.py create mode 100644 auditlog_security/static/description/index.html create mode 160000 maintainer-tools diff --git a/auditlog/:w b/auditlog/:w deleted file mode 100644 index 8b489702eb1..00000000000 --- a/auditlog/:w +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2021 Therp B.V. -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). - -from odoo import models, api - - -class AuditlogAutovacuum(models.TransientModel): - _inherit = 'auditlog.autovacuum' - - @api.model - def autovaccum(self, days): - return super(AuditlogAutovacuum, self.with_context( - auditlog_write=True)).autovacuum(days=days) diff --git a/auditlog/models/rule.py b/auditlog/models/rule.py index e7a3c8f6492..6cdc7233ccd 100644 --- a/auditlog/models/rule.py +++ b/auditlog/models/rule.py @@ -449,8 +449,6 @@ def _create_log_line_on_write( self, log, fields_list, old_values, new_values): """Log field updated on a 'write' operation.""" log_line_model = self.env['auditlog.log.line'] - import pudb - pudb.set_trace() for field_name in fields_list: if field_name in FIELDS_BLACKLIST: continue diff --git a/auditlog/views/auditlog_view.xml b/auditlog/views/auditlog_view.xml index 8eaefc4e36a..2ec7b480896 100644 --- a/auditlog/views/auditlog_view.xml +++ b/auditlog/views/auditlog_view.xml @@ -193,7 +193,7 @@ Logs auditlog.log form - + `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -80,19 +70,12 @@ Credits Authors ~~~~~~~ -* ABF OSIELL +* Therp B.V. Contributors ~~~~~~~~~~~~ -* Sebastien Alix -* Holger Brunn -* Holden Rehg - -Other credits -~~~~~~~~~~~~~ - -* Icon: built with different icons from the `Oxygen theme `_ (LGPL) +* Giovanni Francesco Capalbo Maintainers ~~~~~~~~~~~ @@ -107,6 +90,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/server-tools `_ project on GitHub. +This module is part of the `OCA/server-tools `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/auditlog_security/__manifest__.py b/auditlog_security/__manifest__.py index 5e196c31fa3..782da1100cc 100644 --- a/auditlog_security/__manifest__.py +++ b/auditlog_security/__manifest__.py @@ -2,19 +2,21 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). { - "name": "Audit Log Permissions", - "version": "11.0.1.0.1", + "name": "Audit Log User Permissions", + "version": "11.0.1.0.0", "author": "Therp B.V.,Odoo Community Association (OCA)", "license": "AGPL-3", "website": "https://github.com/OCA/server-tools/", "category": "Tools", + "description": """Allow regular users to view Audit log lines + via the form view of the relevant model""", "depends": [ "auditlog", "contacts", ], "data": [ - "demo/auditlog_rule.xml", "views/auditlog_view.xml", + "security/ir.model.access.csv", ], "application": True, "installable": True, diff --git a/auditlog_security/demo/auditlog_rule.xml b/auditlog_security/demo/auditlog_rule.xml deleted file mode 100644 index eb7639adc6e..00000000000 --- a/auditlog_security/demo/auditlog_rule.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - main auditlog partner rule - - subscribed - - - diff --git a/auditlog_security/models/__init__.py b/auditlog_security/models/__init__.py index aa60319d2a3..4c1c462d621 100644 --- a/auditlog_security/models/__init__.py +++ b/auditlog_security/models/__init__.py @@ -1,5 +1,6 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import auditlog_rule +from . import auditlog_line_access_rule from . import ir_rule from . import auditlog_autovacuum diff --git a/auditlog_security/models/auditlog_autovacuum.py b/auditlog_security/models/auditlog_autovacuum.py index c37db710aaf..7b4b0bc3a19 100644 --- a/auditlog_security/models/auditlog_autovacuum.py +++ b/auditlog_security/models/auditlog_autovacuum.py @@ -8,7 +8,7 @@ class AuditlogAutovacuum(models.TransientModel): _inherit = "auditlog.autovacuum" @api.model - def autovaccum(self, days): + def autovacuum(self, days): return super( AuditlogAutovacuum, self.with_context(auditlog_write=True) ).autovacuum(days=days) diff --git a/auditlog_security/models/auditlog_line_access_rule.py b/auditlog_security/models/auditlog_line_access_rule.py new file mode 100644 index 00000000000..aedb39009f0 --- /dev/null +++ b/auditlog_security/models/auditlog_line_access_rule.py @@ -0,0 +1,115 @@ +# Copyright 2021 Therp B.V. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import exceptions, models, fields, api, modules, _ +from odoo.addons.auditlog.models.rule import FIELDS_BLACKLIST + + +class AuditlogLineAccessRule(models.Model): + _name = "auditlog.line.access.rule" + + name = fields.Char() + + field_ids = fields.Many2many("ir.model.fields") + group_ids = fields.Many2many( + "res.groups", + help="""Groups that will be allowed to see the logged fields, if left empty + default will be all users with a login""", + ) + model_id = fields.Many2one( + "ir.model", related="auditlog_rule_id.model_id", readonly=True + ) + auditlog_rule_id = fields.Many2one( + "auditlog.rule", "auditlog_access_rule_ids", readonly=True, ondelete="cascade" + ) + state = fields.Selection(related="auditlog_rule_id.state", readonly=True) + + + def needs_rule(self): + self.ensure_one() + return bool(self.group_ids) + + def get_linked_rules(self): + # return with context key so that deletion will not be forbidden + return self.env["ir.rule"].search( + [("auditlog_line_access_rule_id", "in", self.ids)] + ) + + def get_field_ids_domain(self): + """note this solution will work only with a hardcoded design of models, + because on initialization , self.model_id.id still is not defined. + for now, to keep generality we put the filtering in the view.""" + return [ + ("model_id", "=", self.env.ref("base.model_res_partner").id), + ("name", "not in", FIELDS_BLACKLIST), + ] + + def unlink(self): + to_delete = self.get_linked_rules() + res = super(AuditlogLineAccessRule, self).unlink() + if res: + res = res and to_delete.with_context(auditlog_write=True).unlink() + return res + + def add_default_group_if_needed(self): + self.ensure_one() + res = False + if not self.group_ids and self.field_ids: + res = self.with_context(no_iter=True).write( + {"group_ids": [(6, 0, [self.env.ref("base.group_user").id])]} + ) + return res + + @api.model + def create(self, vals): + res = super(AuditlogLineAccessRule, self).create(vals) + res.add_default_group_if_needed() + if res.needs_rule(): + res.generate_rules() + return res + + @api.multi + def write(self, vals): + res = super(AuditlogLineAccessRule, self).write(vals) + for this in self: + added = this.add_default_group_if_needed() + if ( + any( + [ + x in vals + for x in ("group_ids", "field_ids", "model_id", "all_fields") + ] + ) + or added + ): + if this.needs_rule(): + this.generate_rules() + else: + this.get_linked_rules().with_context(auditlog_write=True).unlink() + return res + + def generate_rules(self): + old_rule = self.env["ir.rule"].search( + [("auditlog_line_access_rule_id", "=", self.id)], limit=1 + ) + values = self._prepare_rule_values() + if old_rule: + old_rule.with_context(auditlog_write=True).write(values) + else: + self.with_context(auditlog_write=True).env["ir.rule"].create(values) + + def _prepare_rule_values(self): + domain_force = "[" + " ('aulditlog_rule_id.log_id.model_id' , '=', %s)," % ( + self.model_id.id + ) + if self.field_ids: + domain_force += "('field_id', 'in', %s)" % (self.field_ids.ids) + domain_force += "]" + return { + "name": "auditlog_extended_%s" % self.id, + "model_id": self.env.ref("auditlog.model_auditlog_log_line").id, + "groups": [(6, 0, self.group_ids.ids)], + "perm_read": True, + "domain_force": domain_force, + "auditlog_line_access_rule_id": self.id, + } diff --git a/auditlog_security/models/auditlog_rule.py b/auditlog_security/models/auditlog_rule.py index fd45558ca70..4ca5a924395 100644 --- a/auditlog_security/models/auditlog_rule.py +++ b/auditlog_security/models/auditlog_rule.py @@ -1,71 +1,46 @@ # Copyright 2021 Therp B.V. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import models, fields, api, modules, _ +from odoo import exceptions, models, fields, api, modules, _ from odoo.addons.auditlog.models.rule import FIELDS_BLACKLIST class AuditlogRule(models.Model): _inherit = "auditlog.rule" - field_ids = fields.Many2many( - "ir.model.fields", - required=True, + auditlog_line_access_rule_ids = fields.One2many( + "auditlog.line.access.rule", "auditlog_rule_id", ondelete="cascade" ) - group_ids = fields.Many2many( - "res.groups", - string="Groups", - help="""Groups that will be allowed to see the logged fields, if left empty - all groups will be allowed (global rule creation)""", - ) - - """ note this solution will work only with a hardcoded design of models, - because on initialization , self.model_id.id still is not defined. - for now, to keep generality we put the filtering in the view.""" - def get_field_ids_domain(self): - return [ - ("model_id", "=", self.env.ref("base.model_res_partner").id), - ("name", "not in", FIELDS_BLACKLIST), - ] + @api.onchange("model_id") + def onchange_model_id(self): + # if model changes we must wipe out all field ids + self.auditlog_line_access_rule_ids.unlink() + @api.multi def unlink(self): - # if we delete auditlog rule, corresponding ir.rules are removed - # TODO PROPOSAL: a warning here with detailed information? + lines = self.mapped("auditlog_line_access_rule_ids") res = super(AuditlogRule, self).unlink() - return ( - res - and self.env["ir.rule"] - .with_context(auditlog_write=True) - .search([("auditlog_id", "in", self.ids)]) - .unlink() - ) - - @api.multi - def write(self, vals): - res = super(AuditlogRule, self).write(vals) - for this in self: - if any([x in vals for x in ("group_ids", "field_ids", "model_id")]): - this.generate_rules() + if res: + lines.unlink() return res - def generate_rules(self): - old_rule = self.env["ir.rule"].search([("auditlog_id", "=", self.id)], limit=1) - domain_force = ( - "[ " - + " ('log_id.model_id' , '=', %s)," % (self.model_id.id) - + "('field_id', 'in', %s)" % (self.field_ids.ids) - + "]" - ) - values = { - "name": "auditlog_extended_%s" % self.id, - "model_id": self.env.ref("auditlog.model_auditlog_log_line").id, - "groups": [(6, 0, self.group_ids.ids)], - "perm_read": True, - "domain_force": domain_force, - "auditlog_id": self.id, - } - if old_rule: - old_rule.with_context(auditlog_write=True).write(values) - else: - self.with_context(auditlog_write=True).env["ir.rule"].create(values) + @api.multi + def subscribe(self): + super(AuditlogRule, self).subscribe() + act_window_model = self.env["ir.actions.act_window"] + for rule in self: + domain = ( + "[('log_id.model_id', '=', %s), ('log_id.res_id', '=', active_id)]" + % (rule.model_id.id) + ) + vals = { + "name": _("View log lines"), + "res_model": "auditlog.log.line", + "src_model": rule.model_id.model, + "binding_model_id": rule.model_id.id, + "domain": domain, + } + act_window = act_window_model.sudo().create(vals) + rule.write({"state": "subscribed", "action_id": act_window.id}) + return True diff --git a/auditlog_security/models/ir_rule.py b/auditlog_security/models/ir_rule.py index 44176e14afe..dfb1c822fae 100644 --- a/auditlog_security/models/ir_rule.py +++ b/auditlog_security/models/ir_rule.py @@ -7,26 +7,14 @@ class IrRule(models.Model): _inherit = "ir.rule" - auditlog_id = fields.Many2one( - "auditlog.rule", + auditlog_line_access_rule_id = fields.Many2one( + "auditlog.line.access.rule", required=False, - help="Auditlog Rule that generated this ir.rule", + index=True, + ondelete='cascade', + help="Auditlog line access Rule that generated this ir.rule", ) - def prevent_rule_mod(self, vals=None): - auditlog_write = self.env.context.get("auditlog_write") - if "auditlog_id" in vals and not auditlog_write: - raise exceptions.validationerror(_("""Cannot change auditlog_id""")) - for this in self: - if this.auditlog_id and not auditlog_write: - raise exceptions.validationerror( - _( - """ - auditlog line rules are automatically generated from the auditlog - interface, please use that to edit/delete/""" - ) - ) - @api.model def create(self, values): if values.get("model_id") == self.env.ref( @@ -35,18 +23,30 @@ def create(self, values): raise exceptions.ValidationError( _( """ - Auditlog line rules are automatically generated from the auditlog - interface, please use that to create""" + Auditlog line rules are automatically generated from the + auditlog interface, please use that to create""" ) ) return super(IrRule, self).create(values) @api.multi def write(self, vals): - self.prevent_rule_mod(vals) + if "auditlog_id" in vals and not self.env.context.get("auditlog_write"): + raise exceptions.ValidationError( + _("""Cannot change auditlog_line_access_rule""") + ) return super(IrRule, self).write(vals) @api.multi def unlink(self): - self.prevent_rule_mod() + auditlog_write = self.env.context.get("auditlog_write") + for this in self: + if this.auditlog_line_access_rule_id and not auditlog_write: + raise exceptions.ValidationError( + _( + """ + Auditlog line rules are automatically generated from the + auditlog interface, please use that to delete""" + ) + ) return super(IrRule, self).unlink() diff --git a/auditlog_security/readme/USAGE.rst b/auditlog_security/readme/USAGE.rst index 8fa4cd27178..f4cfaeca2cf 100644 --- a/auditlog_security/readme/USAGE.rst +++ b/auditlog_security/readme/USAGE.rst @@ -3,7 +3,8 @@ which operations to log for a given data model. The rule is now extended with a new field permission_ids, that tells us wich groups will be allowed to read the lines produced by this rule. If permission_ids is left empty, the default will be: -"auditlog lines visible only by administrator" +"auditlog lines visible only by user in Settings group, which is the default +for the auditlog module" Then, check logs in the `Settings / Technical / Audit / Logs` menu. You can diff --git a/auditlog_security/security/ir.model.access.csv b/auditlog_security/security/ir.model.access.csv index 005a168ba9d..f5314c702a3 100644 --- a/auditlog_security/security/ir.model.access.csv +++ b/auditlog_security/security/ir.model.access.csv @@ -1,3 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_auditlog_log_line_user,auditlog_log_line_user,model_auditlog_log_line,base.group_user,1,0,0,0 access_auditlog_log_user,auditlog_log_user,model_auditlog_log,base.group_user,1,0,0,0 +access_auditlog_line_access_rule_admin,auditlog_line_access_rule_admin,model_auditlog_line_access_rule,base.group_system,1,1,1,1 diff --git a/auditlog_security/static/description/index.html b/auditlog_security/static/description/index.html new file mode 100644 index 00000000000..03f14d1e6be --- /dev/null +++ b/auditlog_security/static/description/index.html @@ -0,0 +1,438 @@ + + + + + + +Audit Log User Permissions + + + +
+

Audit Log User Permissions

+ + +

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

+

This module allows extends auditlog, allowing specific log lines to be viewed only +by users belonging to specific views, while all other lines are allowed only to +administrator.

+

Table of contents

+ +
+

Usage

+

Go to Settings / Technical / Audit / Rules to subscribe rules. A rule defines +which operations to log for a given data model. +The rule is now extended with a new field permission_ids, that tells us wich groups will +be allowed to read the lines produced by this rule. +If permission_ids is left empty, the default will be: +“auditlog lines visible only by user in Settings group, which is the default +for the auditlog module”

+

Then, check logs in the Settings / Technical / Audit / Logs menu. You can +group them by user sessions, date, data model , HTTP requests.

+
+ +
+

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 smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Therp B.V.
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/server-tools project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/auditlog_security/views/auditlog_view.xml b/auditlog_security/views/auditlog_view.xml index 46df0263ce9..6d34b52e66d 100644 --- a/auditlog_security/views/auditlog_view.xml +++ b/auditlog_security/views/auditlog_view.xml @@ -44,21 +44,59 @@ auditlog.rule - + - - - - - - +

+ Add fields here to make any changes to them (audit log lines) + visible to members of the selected groups. +

+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
@@ -68,47 +106,15 @@ - - + + + + + + + + - - - auditlog.log.search - auditlog.log.line - - - - - - - - - - - - Logs - auditlog.log.line - form - - [('log_id.res_id', '=', active_id)] - - - - - - diff --git a/maintainer-tools b/maintainer-tools new file mode 160000 index 00000000000..7d8a9f9ad73 --- /dev/null +++ b/maintainer-tools @@ -0,0 +1 @@ +Subproject commit 7d8a9f9ad73db0976fb03cbee43d953bc29b89e9