[FIX] base: Module category can reference itself as parent

Steps:
- Update a module category to reference itself as parent
OR
- Update multiple module categories to create a circular dependency (A -> B -> A)

Actual result:
- Upgrade a module is impossible
- Un/Install a module is impossible
- Infinite loop: https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/models/ir_module.py#L900

Expected result:
- Circular dependencies not possible
- Module can be upgrade and un/install

opw-3490162

closes odoo/odoo#149284

X-original-commit: 6932714200d158a21bf10b90b2f71fa5cae0b13f
Signed-off-by: Raphael Collet <rco@odoo.com>
This commit is contained in:
Gaetan Vanden Bergh (gavb)
2024-01-12 21:43:45 +00:00
parent c366efa675
commit 03f2ed8955
3 changed files with 29 additions and 1 deletions
+7 -1
View File
@@ -26,7 +26,7 @@ import psycopg2
import odoo
from odoo import api, fields, models, modules, tools, _
from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG
from odoo.exceptions import AccessDenied, UserError
from odoo.exceptions import AccessDenied, UserError, ValidationError
from odoo.osv import expression
from odoo.tools.parse_version import parse_version
from odoo.tools.misc import topological_sort, get_flag
@@ -98,6 +98,12 @@ class ModuleCategory(models.Model):
for cat in self:
cat.xml_id = xml_ids.get(cat.id, [''])[0]
@api.constrains('parent_id')
def _check_parent_not_circular(self):
if not self._check_recursion():
raise ValidationError(_("Error ! You cannot create recursive categories."))
class MyFilterMessages(Transform):
"""
Custom docutils transform to remove `system message` for a document and
+1
View File
@@ -64,3 +64,4 @@ from . import test_profiler
from . import test_pdf
from . import test_neutralize
from . import test_config_parameter
from . import test_ir_module_category
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestModuleCategory(TransactionCase):
def test_parent_circular_dependencies(self):
Cats = self.env['ir.module.category']
def create(name, **kw):
return Cats.create(dict(kw, name=name))
category_a = create('A', parent_id=False)
category_b = create('B', parent_id=category_a.id)
category_c = create('C', parent_id=category_b.id)
with self.assertRaises(ValidationError):
category_a.write({'parent_id': category_c.id})
with self.assertRaises(ValidationError):
category_b.write({'parent_id': category_b.id})