From bfc066470c02b6954f87ce3c0f3f126ffa386577 Mon Sep 17 00:00:00 2001 From: mreficent Date: Fri, 27 Sep 2019 16:48:05 +0200 Subject: [PATCH] [IMP] Restrict kanban stages only to supported models --- base_kanban_stage/README.rst | 1 + base_kanban_stage/__manifest__.py | 1 + base_kanban_stage/models/__init__.py | 1 + base_kanban_stage/models/base_kanban_stage.py | 5 +- base_kanban_stage/models/ir_model.py | 49 +++++++++++++++++++ .../tests/test_base_kanban_stage.py | 8 +-- base_kanban_stage/views/ir_model_views.xml | 30 ++++++++++++ 7 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 base_kanban_stage/models/ir_model.py create mode 100644 base_kanban_stage/views/ir_model_views.xml diff --git a/base_kanban_stage/README.rst b/base_kanban_stage/README.rst index eaa3953f5..b5421ec1e 100644 --- a/base_kanban_stage/README.rst +++ b/base_kanban_stage/README.rst @@ -93,6 +93,7 @@ Contributors * Oleg Bulkin * Daniel Reis * Alex Comba +* Miquel Raïch Maintainer ---------- diff --git a/base_kanban_stage/__manifest__.py b/base_kanban_stage/__manifest__.py index c77309db4..d91d46ee6 100644 --- a/base_kanban_stage/__manifest__.py +++ b/base_kanban_stage/__manifest__.py @@ -16,6 +16,7 @@ 'security/ir.model.access.csv', 'views/base_kanban_abstract.xml', 'views/base_kanban_stage.xml', + 'views/ir_model_views.xml', ], 'installable': True, 'application': False, diff --git a/base_kanban_stage/models/__init__.py b/base_kanban_stage/models/__init__.py index 4dbc4659f..70a846aed 100644 --- a/base_kanban_stage/models/__init__.py +++ b/base_kanban_stage/models/__init__.py @@ -3,3 +3,4 @@ from . import base_kanban_abstract from . import base_kanban_stage +from . import ir_model diff --git a/base_kanban_stage/models/base_kanban_stage.py b/base_kanban_stage/models/base_kanban_stage.py index c44957b62..883fd5803 100644 --- a/base_kanban_stage/models/base_kanban_stage.py +++ b/base_kanban_stage/models/base_kanban_stage.py @@ -69,13 +69,14 @@ class BaseKanbanStage(models.Model): required=True, index=True, help='The model that this Kanban stage will be used for', - domain=[('transient', '=', False)], + domain=['&', ('is_kanban', '=', True), ('transient', '=', False)], default=lambda s: s._default_res_model_id(), + ondelete='cascade', ) @api.model def _default_res_model_id(self): - '''Useful when creating stages from a Kanban view for another model''' + """Useful when creating stages from a Kanban view for another model""" action_id = self.env.context.get('params', {}).get('action') action = self.env['ir.actions.act_window'].browse(action_id) default_model = action.res_model diff --git a/base_kanban_stage/models/ir_model.py b/base_kanban_stage/models/ir_model.py new file mode 100644 index 000000000..ae5921222 --- /dev/null +++ b/base_kanban_stage/models/ir_model.py @@ -0,0 +1,49 @@ +# Copyright 2019 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class IrModel(models.Model): + _inherit = 'ir.model' + + is_kanban = fields.Boolean( + string="Kanban", default=False, + help="Whether this model support kanban stages.", + ) + + @api.multi + def write(self, vals): + if self and 'is_kanban' in vals: + if not all(rec.state == 'manual' for rec in self): + raise UserError(_('Only custom models can be modified.')) + if not all(rec.is_kanban <= vals['is_kanban'] for rec in self): + raise UserError( + _('Field "Kanban" cannot be changed to "False".')) + res = super(IrModel, self).write(vals) + # setup models; this reloads custom models in registry + self.pool.setup_models(self._cr) + # update database schema of models + models = self.pool.descendants(self.mapped('model'), '_inherits') + self.pool.init_models(self._cr, models, dict( + self._context, update_custom_fields=True)) + else: + res = super(IrModel, self).write(vals) + return res + + def _reflect_model_params(self, model): + vals = super(IrModel, self)._reflect_model_params(model) + vals['is_kanban'] = issubclass( + type(model), self.pool['base.kanban.abstract']) + return vals + + @api.model + def _instanciate(self, model_data): + model_class = super(IrModel, self)._instanciate(model_data) + if model_data.get('is_kanban') and \ + model_class._name != 'base.kanban.abstract': + parents = model_class._inherit or [] + parents = [parents] if isinstance(parents, (str,)) else parents + model_class._inherit = parents + ['base.kanban.abstract'] + return model_class diff --git a/base_kanban_stage/tests/test_base_kanban_stage.py b/base_kanban_stage/tests/test_base_kanban_stage.py index 9184bc811..939165a73 100644 --- a/base_kanban_stage/tests/test_base_kanban_stage.py +++ b/base_kanban_stage/tests/test_base_kanban_stage.py @@ -6,7 +6,7 @@ from odoo.tests.common import TransactionCase class TestBaseKanbanStage(TransactionCase): def test_default_res_model_id_no_params(self): - '''It should return empty ir.model Recordset if no params in context''' + """It should return empty ir.model Recordset if no params in context""" test_stage = self.env['base.kanban.stage'].with_context({}) res_model_id = test_stage._default_res_model_id() @@ -14,7 +14,7 @@ class TestBaseKanbanStage(TransactionCase): self.assertEqual(res_model_id._name, 'ir.model') def test_default_res_model_id_no_action(self): - '''It should return empty ir.model Recordset if no action in params''' + """It should return empty ir.model Recordset if no action in params""" test_stage = self.env['base.kanban.stage'].with_context(params={}) res_model_id = test_stage._default_res_model_id() @@ -22,7 +22,7 @@ class TestBaseKanbanStage(TransactionCase): self.assertEqual(res_model_id._name, 'ir.model') def test_default_res_model_id_info_in_context(self): - '''It should return correct ir.model record if info in context''' + """It should return correct ir.model record if info in context""" test_action = self.env['ir.actions.act_window'].create({ 'name': 'Test Action', 'res_model': 'res.users', @@ -37,7 +37,7 @@ class TestBaseKanbanStage(TransactionCase): ) def test_default_res_model_id_ignore_self(self): - '''It should not return ir.model record corresponding to stage model''' + """It should not return ir.model record corresponding to stage model""" test_action = self.env['ir.actions.act_window'].create({ 'name': 'Test Action', 'res_model': 'base.kanban.stage', diff --git a/base_kanban_stage/views/ir_model_views.xml b/base_kanban_stage/views/ir_model_views.xml new file mode 100644 index 000000000..4b38ed7a1 --- /dev/null +++ b/base_kanban_stage/views/ir_model_views.xml @@ -0,0 +1,30 @@ + + + + + + + + ir.model + + + + + + + + + + ir.model + + + + + + + + +