From 6e671c0fb0da12cbf8e04f3d181d73220d9e78f8 Mon Sep 17 00:00:00 2001 From: Christopher Rogos Date: Mon, 8 Jul 2024 14:25:28 +0000 Subject: [PATCH] [MIG] base_user_role_history: Migration to 17.0 --- base_user_role_history/README.rst | 2 + base_user_role_history/__manifest__.py | 2 +- base_user_role_history/models/__init__.py | 1 + .../models/base_user_role_line_history.py | 91 +-------- base_user_role_history/models/res_users.py | 59 +----- .../models/res_users_role_line.py | 72 +++++++ base_user_role_history/readme/CONTRIBUTORS.md | 2 + .../static/description/index.html | 13 +- base_user_role_history/tests/__init__.py | 1 + .../tests/test_base_user_role_history.py | 5 +- .../tests/test_res_users_role.py | 181 ++++++++++++++++++ .../views/base_user_role_line_history.xml | 20 +- 12 files changed, 297 insertions(+), 152 deletions(-) create mode 100644 base_user_role_history/models/res_users_role_line.py create mode 100644 base_user_role_history/tests/test_res_users_role.py diff --git a/base_user_role_history/README.rst b/base_user_role_history/README.rst index d81bd83e..ae5632fe 100644 --- a/base_user_role_history/README.rst +++ b/base_user_role_history/README.rst @@ -74,6 +74,8 @@ Contributors - Benoit Aimont (https://acsone.eu) - Thomas Binsfeld (https://acsone.eu) +- Christopher Rogos (https://glueckkanja.com) +- Mohamed Osman (https://glueckkanja.com) Maintainers ----------- diff --git a/base_user_role_history/__manifest__.py b/base_user_role_history/__manifest__.py index 218388d7..3ef78094 100644 --- a/base_user_role_history/__manifest__.py +++ b/base_user_role_history/__manifest__.py @@ -5,7 +5,7 @@ "name": "Base User Role History", "summary": """ This module allows to track the changes on users roles.""", - "version": "16.0.1.0.0", + "version": "17.0.1.0.0", "license": "AGPL-3", "author": "ACSONE SA/NV, " "Odoo Community Association (OCA)", "website": "https://github.com/OCA/server-backend", diff --git a/base_user_role_history/models/__init__.py b/base_user_role_history/models/__init__.py index 9ce69302..96d05ca4 100644 --- a/base_user_role_history/models/__init__.py +++ b/base_user_role_history/models/__init__.py @@ -1,2 +1,3 @@ from . import res_users from . import base_user_role_line_history +from . import res_users_role_line diff --git a/base_user_role_history/models/base_user_role_line_history.py b/base_user_role_history/models/base_user_role_line_history.py index 328fe5bf..4302a0e6 100644 --- a/base_user_role_history/models/base_user_role_line_history.py +++ b/base_user_role_history/models/base_user_role_line_history.py @@ -1,7 +1,7 @@ # Copyright 2019 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models +from odoo import fields, models class BaseUserRoleLineHistory(models.Model): @@ -13,105 +13,28 @@ class BaseUserRoleLineHistory(models.Model): string="Action", selection=[("add", "Add"), ("unlink", "Delete"), ("edit", "Edit")], required=True, - readonly=True, ) user_id = fields.Many2one( string="User", comodel_name="res.users", ondelete="cascade", - readonly=True, index=True, ) old_role_id = fields.Many2one( string="Old role", comodel_name="res.users.role", ondelete="cascade", - readonly=True, index=True, ) new_role_id = fields.Many2one( string="New role", comodel_name="res.users.role", ondelete="cascade", - readonly=True, index=True, ) - old_date_from = fields.Date(string="Old start date", readonly=True) - new_date_from = fields.Date(string="New start date", readonly=True) - old_date_to = fields.Date(string="Old end date", readonly=True) - new_date_to = fields.Date(string="New end date", readonly=True) - old_is_enabled = fields.Boolean(string="Active before edit", readonly=True) - new_is_enabled = fields.Boolean(string="Active after edit", readonly=True) - - @api.model - def _prepare_create_from_vals( - self, old_role_line_values_by_user, new_role_line_values_by_user - ): - role_history_line_vals_by_role_line = {} - for key, value in new_role_line_values_by_user.items(): - old_vals = old_role_line_values_by_user.get(key, {}) - new_vals = value - # Manage deletion of role lines and old values of modified lines - for role_line_id, role_line_vals in old_vals.items(): - action = "unlink" if role_line_id not in new_vals else "edit" - if action == "edit": - # Skip if no change - if not any( - role_line_vals[k] != new_vals[role_line_id][k] - for k in role_line_vals - ): - continue - role_history_line_vals_by_role_line.setdefault(role_line_id, {}) - role_history_line_vals_by_role_line[role_line_id].update( - { - "performed_action": action, - "user_id": role_line_vals["user_id"], - "old_role_id": role_line_vals["role_id"], - "old_date_from": role_line_vals["date_from"], - "old_date_to": role_line_vals["date_to"], - "old_is_enabled": role_line_vals["is_enabled"], - } - ) - # Manage addition of role lines and new values of modified ones - for role_line_id, role_line_vals in new_vals.items(): - action = "add" if role_line_id not in old_vals else "edit" - if action == "edit": - # Skip if no change - if not any( - role_line_vals[k] != old_vals[role_line_id][k] - for k in role_line_vals - ): - continue - role_history_line_vals_by_role_line.setdefault(role_line_id, {}) - role_history_line_vals_by_role_line[role_line_id].update( - { - "performed_action": action, - "user_id": role_line_vals["user_id"], - "new_role_id": role_line_vals["role_id"], - "new_date_from": role_line_vals["date_from"], - "new_date_to": role_line_vals["date_to"], - "new_is_enabled": role_line_vals["is_enabled"], - } - ) - return role_history_line_vals_by_role_line - - @api.model - def create_from_vals( - self, old_role_line_values_by_user, new_role_line_values_by_user - ): - """ - This method creates user role line history objects based on given - old/new values. - old_role_line_values_by_user and new_role_line_values_by_user are like: - {user_id: - {role_line_id: - {role_line_values}, - }, - } - """ - role_history_line_vals_by_role_line = self._prepare_create_from_vals( - old_role_line_values_by_user, new_role_line_values_by_user - ) - # Create the history lines with sudo - # (nobody has the create right) - self.sudo().create(list(role_history_line_vals_by_role_line.values())) + old_date_from = fields.Date(string="Old start date") + new_date_from = fields.Date(string="New start date") + old_date_to = fields.Date(string="Old end date") + new_date_to = fields.Date(string="New end date") + old_is_enabled = fields.Boolean(string="Active before edit") + new_is_enabled = fields.Boolean(string="Active after edit") diff --git a/base_user_role_history/models/res_users.py b/base_user_role_history/models/res_users.py index 2a408287..d6c90c22 100644 --- a/base_user_role_history/models/res_users.py +++ b/base_user_role_history/models/res_users.py @@ -1,65 +1,22 @@ # Copyright 2019 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import _, api, fields, models +from odoo import _, fields, models class ResUsers(models.Model): _inherit = "res.users" last_role_line_modification = fields.Datetime( - string="Last roles modification", readonly=True + compute="_compute_last_role_line_modification", ) - @api.model - def _prepare_role_line_history_dict(self, role_line): - return { - "user_id": role_line.user_id.id, - "role_id": role_line.role_id.id, - "date_from": role_line.date_from, - "date_to": role_line.date_to, - "is_enabled": role_line.is_enabled, - } - - def _get_role_line_values_by_user(self): - role_line_values_by_user = {} - for rec in self: - role_line_values_by_user.setdefault(rec, {}) - for role_line in rec.role_line_ids: - role_line_values_by_user[rec][ - role_line.id - ] = self._prepare_role_line_history_dict(role_line) - return role_line_values_by_user - - @api.model_create_multi - def create(self, vals_list): - res = super().create(vals_list) - if all("role_line_ids" not in vals for vals in vals_list): - return res - new_role_line_values_by_user = res._get_role_line_values_by_user() - new_role_line_to_create = {} - users = self.browse() - for user, lines in new_role_line_values_by_user.items(): - if lines: - new_role_line_to_create[user] = lines - user |= user - self.env["base.user.role.line.history"].create_from_vals( - {}, new_role_line_to_create - ) - users.last_role_line_modification = fields.Datetime.now() - return res - - def write(self, vals): - if "role_line_ids" not in vals: - return super().write(vals) - old_role_line_values_by_user = self._get_role_line_values_by_user() - vals["last_role_line_modification"] = fields.Datetime.now() - res = super().write(vals) - new_role_line_values_by_user = self._get_role_line_values_by_user() - self.env["base.user.role.line.history"].create_from_vals( - old_role_line_values_by_user, new_role_line_values_by_user - ) - return res + def _compute_last_role_line_modification(self): + for user in self: + res = self.env["base.user.role.line.history"].search( + [("user_id", "=", user.id)], limit=1, order="id desc" + ) + user.last_role_line_modification = res.create_date if res else False def show_role_lines_history(self): # pragma: no cover self.ensure_one() diff --git a/base_user_role_history/models/res_users_role_line.py b/base_user_role_history/models/res_users_role_line.py new file mode 100644 index 00000000..5747cc9a --- /dev/null +++ b/base_user_role_history/models/res_users_role_line.py @@ -0,0 +1,72 @@ +from odoo import api, models + + +class ResUsersRoleLine(models.Model): + _inherit = "res.users.role.line" + + def write(self, vals): + history_lines = [] + for line in self: + history_line = { + "performed_action": "edit", + "user_id": line.user_id.id, + "old_role_id": line.role_id.id, + "old_date_from": line.date_from, + "old_date_to": line.date_to, + "old_is_enabled": line.is_enabled, + "new_role_id": vals.get("role_id", line.role_id.id), + "new_date_from": vals.get("date_from", line.date_from), + "new_date_to": vals.get("date_to", line.date_to), + "new_is_enabled": vals.get("is_enabled", line.is_enabled), + } + if ( + history_line["old_role_id"] == history_line["new_role_id"] + and history_line["old_date_from"] == history_line["new_date_from"] + and history_line["old_date_to"] == history_line["new_date_to"] + and history_line["old_is_enabled"] == history_line["new_is_enabled"] + ): + continue + + history_lines.append(history_line) + + res = super().write(vals) + self.env["base.user.role.line.history"].sudo().create(history_lines) + + return res + + @api.model_create_multi + def create(self, vals_list): + history_lines = [] + for line in vals_list: + history_line = { + "performed_action": "add", + "user_id": line.get("user_id", False), + "new_role_id": line.get("role_id", False), + "new_date_from": line.get("date_from", False), + "new_date_to": line.get("date_to", False), + "new_is_enabled": line.get("is_enabled", True), + } + history_lines.append(history_line) + + res = super().create(vals_list) + self.env["base.user.role.line.history"].sudo().create(history_lines) + + return res + + def unlink(self): + history_lines = [] + for line in self: + history_line = { + "performed_action": "unlink", + "user_id": line.user_id.id, + "old_role_id": line.role_id.id, + "old_date_from": line.date_from, + "old_date_to": line.date_to, + "old_is_enabled": line.is_enabled, + } + history_lines.append(history_line) + + res = super().unlink() + self.env["base.user.role.line.history"].sudo().create(history_lines) + + return res diff --git a/base_user_role_history/readme/CONTRIBUTORS.md b/base_user_role_history/readme/CONTRIBUTORS.md index 74230a27..9492cc47 100644 --- a/base_user_role_history/readme/CONTRIBUTORS.md +++ b/base_user_role_history/readme/CONTRIBUTORS.md @@ -1,2 +1,4 @@ - Benoit Aimont \<\> () - Thomas Binsfeld \<\> () +- Christopher Rogos \<\> () +- Mohamed Osman \<\> () \ No newline at end of file diff --git a/base_user_role_history/static/description/index.html b/base_user_role_history/static/description/index.html index 70a10f4d..0f938604 100644 --- a/base_user_role_history/static/description/index.html +++ b/base_user_role_history/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code { margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.option { span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -419,12 +420,16 @@ If you spotted it first, help us to smash it by providing a detailed and welcome

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +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.

diff --git a/base_user_role_history/tests/__init__.py b/base_user_role_history/tests/__init__.py index c9a4ca3c..50ed093c 100644 --- a/base_user_role_history/tests/__init__.py +++ b/base_user_role_history/tests/__init__.py @@ -1 +1,2 @@ from . import test_base_user_role_history +from . import test_res_users_role diff --git a/base_user_role_history/tests/test_base_user_role_history.py b/base_user_role_history/tests/test_base_user_role_history.py index fa81febf..33ee4c75 100644 --- a/base_user_role_history/tests/test_base_user_role_history.py +++ b/base_user_role_history/tests/test_base_user_role_history.py @@ -6,10 +6,11 @@ from datetime import date, timedelta from odoo.tests.common import TransactionCase +# DEPRECATED: This tests are deprecated but stay to show that the new code is working. class TestBaseUserRoleHistory(TransactionCase): @classmethod def setUpClass(cls): - super(TestBaseUserRoleHistory, cls).setUpClass() + super().setUpClass() cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) # MODELS @@ -138,4 +139,4 @@ class TestBaseUserRoleHistory(TransactionCase): """ new_user = self.user_model.create({"login": "new_user", "name": "new_user"}) history_lines = self.history_line_model.search([("user_id", "=", new_user.id)]) - self.assertFalse(history_lines) + self.assertEqual(len(history_lines), 0) diff --git a/base_user_role_history/tests/test_res_users_role.py b/base_user_role_history/tests/test_res_users_role.py new file mode 100644 index 00000000..c21a796e --- /dev/null +++ b/base_user_role_history/tests/test_res_users_role.py @@ -0,0 +1,181 @@ +from datetime import date + +from odoo.tests.common import TransactionCase + + +class TestResUsersRole(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.ResUsers = cls.env["res.users"] + cls.ResUsersRole = cls.env["res.users.role"] + cls.ResUsersRoleLine = cls.env["res.users.role.line"] + cls.BaseUserRoleLineHistory = cls.env["base.user.role.line.history"] + + cls.user = cls.ResUsers.create( + { + "name": "Test user 01", + "login": "test1", + } + ) + + def test_create_adds_history(self): + # act + role_01 = self.ResUsersRole.create( + {"name": "Test role 01", "line_ids": [(0, 0, {"user_id": self.user.id})]} + ) + + # assert + self.assertTrue(role_01.name, "Test role 01") + + history_lines_all = self.BaseUserRoleLineHistory.search( + [("user_id", "=", self.user.id)] + ) + self.assertEqual(len(history_lines_all), 1) + + history_line_1 = history_lines_all[0] + self.assertEqual(history_line_1.user_id, self.user) + self.assertEqual(history_line_1.performed_action, "add") + self.assertFalse(history_line_1.old_role_id) + self.assertEqual(history_line_1.new_role_id, role_01) + self.assertFalse(history_line_1.old_is_enabled) + self.assertTrue(history_line_1.new_is_enabled) + + def test_write_adds_history_entry(self): + # arrange + role_01 = self.ResUsersRole.create( + {"name": "Test role 01", "line_ids": [(0, 0, {"user_id": self.user.id})]} + ) + + role_01_line = role_01.line_ids[0] + + # act + role_01_line.write( + { + "date_from": "2024-05-01", + "date_to": "2024-05-30", + } + ) + + # assert + history_lines_all = self.BaseUserRoleLineHistory.search( + [("user_id", "=", self.user.id)] + ) + + self.assertEqual(len(history_lines_all), 2) + + history_lines_add = history_lines_all.filtered( + lambda x: x.performed_action == "edit" + ) + self.assertEqual(len(history_lines_add), 1) + + history_line_1 = history_lines_add[0] + self.assertEqual(history_line_1.performed_action, "edit") + self.assertFalse(history_line_1.old_date_from) + self.assertEqual(history_line_1.new_date_from, date(2024, 5, 1)) + self.assertFalse(history_line_1.old_date_to) + self.assertEqual(history_line_1.new_date_to, date(2024, 5, 30)) + self.assertTrue(history_line_1.old_is_enabled) + self.assertTrue(history_line_1.new_is_enabled) + + def test_write_no_history_entry(self): + # arrange + role_01 = self.ResUsersRole.create( + { + "name": "Test role 01", + "line_ids": [ + ( + 0, + 0, + { + "user_id": self.user.id, + "date_from": "2024-05-01", + "date_to": "2024-05-30", + }, + ) + ], + } + ) + + role_01_line = role_01.line_ids[0] + + # act + # write same values again + role_01_line.write( + { + "date_from": "2024-05-01", + "date_to": "2024-05-30", + } + ) + + # assert + history_lines_all = self.BaseUserRoleLineHistory.search( + [("user_id", "=", self.user.id)] + ) + + self.assertTrue(len(history_lines_all), 1) + history_lines_edit = history_lines_all.filtered( + lambda x: x.performed_action == "edit" + ) + self.assertTrue(len(history_lines_edit), 0) + + def test_create_adds_history_entry(self): + # arrange + role_01 = self.ResUsersRole.create({"name": "Test role 01", "line_ids": []}) + + # act + self.ResUsersRoleLine.create( + { + "role_id": role_01.id, + "user_id": self.user.id, + "date_from": "2024-05-01", + "date_to": "2024-05-30", + } + ) + + # assert + history_line_add = self.BaseUserRoleLineHistory.search( + [("user_id", "=", self.user.id), ("performed_action", "=", "add")] + ) + + self.assertEqual(len(history_line_add), 1) + history_line_1 = history_line_add[0] + self.assertFalse(history_line_1.old_role_id) + self.assertEqual(history_line_1.new_role_id, role_01) + self.assertFalse(history_line_1.old_date_from) + self.assertEqual(history_line_1.new_date_from, date(2024, 5, 1)) + self.assertFalse(history_line_1.old_date_to) + self.assertEqual(history_line_1.new_date_to, date(2024, 5, 30)) + self.assertFalse(history_line_1.old_is_enabled) + self.assertTrue(history_line_1.new_is_enabled) + + def test_unlink_adds_history_entry(self): + # arrange + role_01 = self.ResUsersRole.create( + {"name": "Test role 01", "line_ids": [(0, 0, {"user_id": self.user.id})]} + ) + + # act + role_01.line_ids[0].unlink() + + # assert + history_line_all = self.BaseUserRoleLineHistory.search( + [("user_id", "=", self.user.id)] + ) + + self.assertEqual(len(history_line_all), 2) + + history_lines_unlink = history_line_all.filtered( + lambda x: x.performed_action == "unlink" + ) + self.assertEqual(len(history_lines_unlink), 1) + + history_line_1 = history_lines_unlink[0] + self.assertEqual(history_line_1.old_role_id, role_01) + self.assertFalse(history_line_1.new_role_id) + self.assertFalse(history_line_1.old_date_from) + self.assertFalse(history_line_1.new_date_from) + self.assertFalse(history_line_1.old_date_to) + self.assertFalse(history_line_1.new_date_to) + self.assertTrue(history_line_1.old_is_enabled) + self.assertFalse(history_line_1.new_is_enabled) diff --git a/base_user_role_history/views/base_user_role_line_history.xml b/base_user_role_history/views/base_user_role_line_history.xml index 8031ba34..2eb1bd9d 100644 --- a/base_user_role_history/views/base_user_role_line_history.xml +++ b/base_user_role_history/views/base_user_role_line_history.xml @@ -15,17 +15,17 @@ - - + + - - - - - - - - + + + + + + + +