Browse Source

Drop bi views when uninstalling module

pull/293/head
Andrea Stirpe 6 years ago
committed by Andrea
parent
commit
205433abb1
  1. 2
      bi_view_editor/__init__.py
  2. 3
      bi_view_editor/__manifest__.py
  3. 59
      bi_view_editor/hooks.py
  4. 4
      bi_view_editor/models/ir_model.py
  5. 120
      bi_view_editor/models/models.py
  6. 4
      bi_view_editor/static/src/js/bi_view_editor.JoinNodeDialog.js
  7. 6
      bi_view_editor/tests/test_bi_view.py
  8. 8
      bi_view_editor/wizard/wizard_ir_model_menu_create.py

2
bi_view_editor/__init__.py

@ -2,4 +2,4 @@
from . import models from . import models
from . import wizard from . import wizard
from .hooks import uninstall_hook
from .hooks import post_load, uninstall_hook

3
bi_view_editor/__manifest__.py

@ -24,6 +24,7 @@
'qweb': [ 'qweb': [
'static/src/xml/bi_view_editor.xml' 'static/src/xml/bi_view_editor.xml'
], ],
'post_load': 'post_load',
'uninstall_hook': 'uninstall_hook',
'installable': True, 'installable': True,
'uninstall_hook': 'uninstall_hook'
} }

59
bi_view_editor/hooks.py

@ -1,6 +1,56 @@
# Copyright 2015-2018 Onestein (<http://www.onestein.eu>) # Copyright 2015-2018 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging
from odoo import SUPERUSER_ID
from odoo import api, modules
from odoo.tools import existing_tables, topological_sort
_logger = logging.getLogger(__name__)
def _bi_view(_name):
return _name[0:6] == 'x_bve.'
def post_load():
def check_tables_exist(self, cr):
"""
Verify that all tables are present and try to initialize
those that are missing.
"""
# This monkey patch is meant to avoid that the _logger writes
# warning and error messages, while running an update all,
# in case the model is a bi-view-generated model.
env = api.Environment(cr, SUPERUSER_ID, {})
table2model = {
model._table: name for name, model in env.items()
if not model._abstract and not _bi_view(name) # here is the patch
}
missing_tables = set(table2model).difference(
existing_tables(cr, table2model))
if missing_tables:
missing = {table2model[table] for table in missing_tables}
_logger.warning("Models have no table: %s.", ", ".join(missing))
# recreate missing tables following model dependencies
deps = {name: model._depends for name, model in env.items()}
for name in topological_sort(deps):
if name in missing:
_logger.info("Recreate table of model %s.", name)
env[name].init()
# check again, and log errors if tables are still missing
missing_tables = set(table2model).difference(
existing_tables(cr, table2model))
for table in missing_tables:
_logger.error("Model %s has no table.", table2model[table])
modules.registry.Registry.check_tables_exist = check_tables_exist
def uninstall_hook(cr, registry): def uninstall_hook(cr, registry):
# delete dirty data that could cause problems # delete dirty data that could cause problems
@ -11,3 +61,12 @@ def uninstall_hook(cr, registry):
cr.execute(""" cr.execute("""
delete from bve_view where model_name like 'x_bve.%' delete from bve_view where model_name like 'x_bve.%'
""") """)
cr.execute("""
SELECT 'DROP VIEW ' || table_name
FROM information_schema.views
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_name like 'x_bve_%'
""")
results = list(cr.fetchall())
for result in results:
cr.execute(result[0])

4
bi_view_editor/models/ir_model.py

@ -270,7 +270,7 @@ class IrModel(models.Model):
@api.model @api.model
def create(self, vals): def create(self, vals):
if self._context and self._context.get('bve'):
if self.env.context and self.env.context.get('bve'):
vals['state'] = 'base' vals['state'] = 'base'
res = super(IrModel, self).create(vals) res = super(IrModel, self).create(vals)
@ -281,7 +281,7 @@ class IrModel(models.Model):
self.env.cr.execute(q, (res.id, )) self.env.cr.execute(q, (res.id, ))
# # update registry # # update registry
if self._context.get('bve'):
if self.env.context.get('bve'):
# setup models; this reloads custom models in registry # setup models; this reloads custom models in registry
self.pool.setup_models(self._cr) self.pool.setup_models(self._cr)

120
bi_view_editor/models/models.py

@ -3,12 +3,9 @@
import logging import logging
from odoo import SUPERUSER_ID
from odoo import _, api, models, modules, tools
from odoo import _, api, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
from odoo.tools import (existing_tables, topological_sort)
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -17,122 +14,22 @@ def _bi_view(_name):
return _name[0:6] == 'x_bve.' return _name[0:6] == 'x_bve.'
def check_tables_exist(self, cr):
"""
Verify that all tables are present and try to initialize
those that are missing.
"""
# This monkey patch is meant to avoid that the _logger writes
# warning and error messages, while running an update all,
# in case the model is a bi-view-generated model.
env = api.Environment(cr, SUPERUSER_ID, {})
table2model = {
model._table: name for name, model in env.items()
if not model._abstract and not _bi_view(name) # here is the patch
}
missing_tables = set(table2model).difference(
existing_tables(cr, table2model))
if missing_tables:
missing = {table2model[table] for table in missing_tables}
_logger.warning("Models have no table: %s.", ", ".join(missing))
# recreate missing tables following model dependencies
deps = {name: model._depends for name, model in env.items()}
for name in topological_sort(deps):
if name in missing:
_logger.info("Recreate table of model %s.", name)
env[name].init()
# check again, and log errors if tables are still missing
missing_tables = set(table2model).difference(
existing_tables(cr, table2model))
for table in missing_tables:
_logger.error("Model %s has no table.", table2model[table])
modules.registry.Registry.check_tables_exist = check_tables_exist
_auto_init_orig = models.BaseModel._auto_init
@api.model_cr_context @api.model_cr_context
def _auto_init(self): def _auto_init(self):
""" Initialize the database schema of ``self``:
- create the corresponding table,
- create/update the necessary columns/tables for fields,
- initialize new columns on existing rows,
- add the SQL constraints given on the model,
- add the indexes on indexed fields,
Also prepare post-init stuff to:
- add foreign key constraints,
- reflect models, fields, relations and constraints,
- mark fields to recompute on existing records.
Note: you should not override this method. Instead, you can modify
the model's database schema by overriding method :meth:`~.init`,
which is called right after this one.
"""
# This monkey patch is meant to fix an error (probably # This monkey patch is meant to fix an error (probably
# introduced by https://github.com/odoo/odoo/pull/15412), while # introduced by https://github.com/odoo/odoo/pull/15412), while
# running an update all. The _auto_init() method invoked during # running an update all. The _auto_init() method invoked during
# an update all is the one of BaseModel, and not the one of Base. # an update all is the one of BaseModel, and not the one of Base.
# START OF patch
# This monkey patch seems not working if defined inside the post_load()
if _bi_view(self._name): if _bi_view(self._name):
return return
# END of patch
models.raise_on_invalid_object_name(self._name)
# This prevents anything called by this method (in particular default
# values) from prefetching a field for which the corresponding column
# has not been added in database yet!
self = self.with_context(prefetch_fields=False)
self.pool.post_init(self._reflect)
cr = self._cr
parent_store_compute = False
update_custom_fields = self._context.get('update_custom_fields', False)
must_create_table = not tools.table_exists(cr, self._table)
if self._auto:
if must_create_table:
tools.create_model_table(cr, self._table, self._description)
if self._parent_store:
if not tools.column_exists(cr, self._table, 'parent_left'):
self._create_parent_columns()
parent_store_compute = True
self._check_removed_columns(log=False)
# update the database schema for fields
columns = tools.table_columns(cr, self._table)
def recompute(field):
_logger.info("Storing computed values of %s", field)
recs = self.with_context(active_test=False).search([])
recs._recompute_todo(field)
for field in self._fields.values():
if not field.store:
continue
if field.manual and not update_custom_fields:
continue # don't update custom fields
new = field.update_db(self, columns)
if new and field.compute:
self.pool.post_init(recompute, field)
if self._auto:
self._add_sql_constraints()
if must_create_table:
self._execute_sql()
if parent_store_compute:
self._parent_store_compute()
return _auto_init_orig(self)
models.BaseModel._auto_init = _auto_init models.BaseModel._auto_init = _auto_init
@ -141,11 +38,6 @@ models.BaseModel._auto_init = _auto_init
class Base(models.AbstractModel): class Base(models.AbstractModel):
_inherit = 'base' _inherit = 'base'
@api.model
def _auto_init(self):
if not _bi_view(self._name):
super(Base, self)._auto_init()
@api.model @api.model
def _setup_complete(self): def _setup_complete(self):
if not _bi_view(self._name): if not _bi_view(self._name):

4
bi_view_editor/static/src/js/bi_view_editor.JoinNodeDialog.js

@ -14,7 +14,7 @@ odoo.define('bi_view_editor.JoinNodeDialog', function (require) {
'/bi_view_editor/static/src/xml/bi_view_editor.xml' '/bi_view_editor/static/src/xml/bi_view_editor.xml'
]), ]),
events: { events: {
"click li": "choiceClicked",
"click li": "choiceClicked"
}, },
init: function (parent, options, choices, model_data) { init: function (parent, options, choices, model_data) {
this.choices = choices; this.choices = choices;
@ -36,7 +36,7 @@ odoo.define('bi_view_editor.JoinNodeDialog', function (require) {
text: _t("Cancel"), text: _t("Cancel"),
classes: "btn-default o_form_button_cancel", classes: "btn-default o_form_button_cancel",
close: true close: true
}],
}]
}); });
this._super(parent, defaults); this._super(parent, defaults);
}, },

6
bi_view_editor/tests/test_bi_view.py

@ -239,11 +239,11 @@ class TestBiViewEditor(TransactionCase):
'name': "Test View5", 'name': "Test View5",
'group_ids': [(6, 0, [employees_group.id])], 'group_ids': [(6, 0, [employees_group.id])],
}) })
l = list()
data_list = list()
for r in json.loads(vals['data']): for r in json.loads(vals['data']):
r['model_name'] = "model'name" r['model_name'] = "model'name"
l.append(r)
new_format_data = json.dumps(l)
data_list.append(r)
new_format_data = json.dumps(data_list)
vals.update({'data': new_format_data}) vals.update({'data': new_format_data})
bi_view = self.env['bve.view'].create(vals) bi_view = self.env['bve.view'].create(vals)
self.assertEqual(len(bi_view), 1) self.assertEqual(len(bi_view), 1)

8
bi_view_editor/wizard/wizard_ir_model_menu_create.py

@ -9,9 +9,9 @@ class WizardModelMenuCreate(models.TransientModel):
@api.multi @api.multi
def menu_create(self): def menu_create(self):
if self._context.get('active_model') == 'bve.view':
if self.env.context.get('active_model') == 'bve.view':
self.ensure_one() self.ensure_one()
active_id = self._context.get('active_id')
active_id = self.env.context.get('active_id')
bve_view = self.env['bve.view'].browse(active_id) bve_view = self.env['bve.view'].browse(active_id)
menu = self.env['ir.ui.menu'].create({ menu = self.env['ir.ui.menu'].create({
'name': self.name, 'name': self.name,
@ -31,8 +31,8 @@ class WizardModelMenuCreate(models.TransientModel):
@api.model @api.model
def default_get(self, fields_list): def default_get(self, fields_list):
defaults = super(WizardModelMenuCreate, self).default_get(fields_list) defaults = super(WizardModelMenuCreate, self).default_get(fields_list)
if self._context.get('active_model') == 'bve.view':
active_id = self._context.get('active_id')
if self.env.context.get('active_model') == 'bve.view':
active_id = self.env.context.get('active_id')
bve_view = self.env['bve.view'].browse(active_id) bve_view = self.env['bve.view'].browse(active_id)
defaults.setdefault('name', bve_view.name) defaults.setdefault('name', bve_view.name)
return defaults return defaults
Loading…
Cancel
Save