diff --git a/database_cleanup/__openerp__.py b/database_cleanup/__openerp__.py index 7c535deca..24600036e 100644 --- a/database_cleanup/__openerp__.py +++ b/database_cleanup/__openerp__.py @@ -1,23 +1,23 @@ # Copyright 2014-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { - 'name': 'Database cleanup', - 'version': '12.0.1.0.1', - 'author': "Therp BV,Odoo Community Association (OCA)", - 'depends': ['base'], - 'license': 'AGPL-3', - 'category': 'Tools', - 'data': [ + "name": "Database cleanup", + "version": "12.0.1.0.1", + "author": "Therp BV,Odoo Community Association (OCA)", + "depends": ["base"], + "license": "AGPL-3", + "category": "Tools", + "data": [ "views/purge_wizard.xml", - 'views/purge_menus.xml', - 'views/purge_modules.xml', - 'views/purge_models.xml', - 'views/purge_columns.xml', - 'views/purge_tables.xml', - 'views/purge_data.xml', + "views/purge_menus.xml", + "views/purge_modules.xml", + "views/purge_models.xml", + "views/purge_columns.xml", + "views/purge_tables.xml", + "views/purge_data.xml", "views/create_indexes.xml", - 'views/purge_properties.xml', - 'views/menu.xml', + "views/purge_properties.xml", + "views/menu.xml", ], - 'installable': True, + "installable": True, } diff --git a/database_cleanup/identifier_adapter.py b/database_cleanup/identifier_adapter.py index a10dc2e00..da05fda82 100644 --- a/database_cleanup/identifier_adapter.py +++ b/database_cleanup/identifier_adapter.py @@ -14,11 +14,9 @@ class IdentifierAdapter(ISQLQuote): def getquoted(self): def is_identifier_char(c): - return c.isalnum() or c in ['_', '$'] + return c.isalnum() or c in ["_", "$"] format_string = '"%s"' if not self.quote: - format_string = '%s' - return format_string % ''.join( - filter(is_identifier_char, self.identifier) - ) + format_string = "%s" + return format_string % "".join(filter(is_identifier_char, self.identifier)) diff --git a/database_cleanup/models/create_indexes.py b/database_cleanup/models/create_indexes.py index 9ff571522..669d8051f 100644 --- a/database_cleanup/models/create_indexes.py +++ b/database_cleanup/models/create_indexes.py @@ -1,26 +1,27 @@ # Copyright 2017 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # pylint: disable=consider-merging-classes-inherited -from ..identifier_adapter import IdentifierAdapter from odoo import api, fields, models +from ..identifier_adapter import IdentifierAdapter + class CreateIndexesLine(models.TransientModel): - _inherit = 'cleanup.purge.line' - _name = 'cleanup.create_indexes.line' + _inherit = "cleanup.purge.line" + _name = "cleanup.create_indexes.line" - purged = fields.Boolean('Created') - wizard_id = fields.Many2one('cleanup.create_indexes.wizard') - field_id = fields.Many2one('ir.model.fields', required=True) + purged = fields.Boolean("Created") + wizard_id = fields.Many2one("cleanup.create_indexes.wizard") + field_id = fields.Many2one("ir.model.fields", required=True) @api.multi def purge(self): tables = set() - for field in self.mapped('field_id'): + for field in self.mapped("field_id"): model = self.env[field.model] - name = '%s_%s_index' % (model._table, field.name) + name = "{}_{}_index".format(model._table, field.name) self.env.cr.execute( - 'create index %s ON %s (%s)', + "create index %s ON %s (%s)", ( IdentifierAdapter(name, quote=False), IdentifierAdapter(model._table), @@ -29,54 +30,66 @@ class CreateIndexesLine(models.TransientModel): ) tables.add(model._table) for table in tables: - self.env.cr.execute( - 'analyze %s', (IdentifierAdapter(model._table),) - ) - self.write({ - 'purged': True, - }) + self.env.cr.execute("analyze %s", (IdentifierAdapter(model._table),)) + self.write( + { + "purged": True, + } + ) class CreateIndexesWizard(models.TransientModel): - _inherit = 'cleanup.purge.wizard' - _name = 'cleanup.create_indexes.wizard' - _description = 'Create indexes' + _inherit = "cleanup.purge.wizard" + _name = "cleanup.create_indexes.wizard" + _description = "Create indexes" purge_line_ids = fields.One2many( - 'cleanup.create_indexes.line', 'wizard_id', + "cleanup.create_indexes.line", + "wizard_id", ) @api.multi def find(self): res = list() - for field in self.env['ir.model.fields'].search([ - ('index', '=', True), - ]): + for field in self.env["ir.model.fields"].search( + [ + ("index", "=", True), + ] + ): if field.model not in self.env.registry: continue model = self.env[field.model] - name = '%s_%s_index' % (model._table, field.name) + name = "{}_{}_index".format(model._table, field.name) self.env.cr.execute( - 'select indexname from pg_indexes ' - 'where indexname=%s and tablename=%s', - (name, model._table) + "select indexname from pg_indexes " + "where indexname=%s and tablename=%s", + (name, model._table), ) if self.env.cr.rowcount: continue self.env.cr.execute( - 'select a.attname ' - 'from pg_attribute a ' - 'join pg_class c on a.attrelid=c.oid ' - 'join pg_tables t on t.tablename=c.relname ' - 'where attname=%s and c.relname=%s', - (field.name, model._table,) + "select a.attname " + "from pg_attribute a " + "join pg_class c on a.attrelid=c.oid " + "join pg_tables t on t.tablename=c.relname " + "where attname=%s and c.relname=%s", + ( + field.name, + model._table, + ), ) if not self.env.cr.rowcount: continue - res.append((0, 0, { - 'name': '%s.%s' % (field.model, field.name), - 'field_id': field.id, - })) + res.append( + ( + 0, + 0, + { + "name": "{}.{}".format(field.model, field.name), + "field_id": field.id, + }, + ) + ) return res diff --git a/database_cleanup/models/purge_columns.py b/database_cleanup/models/purge_columns.py index 623cb4983..db198c6a6 100644 --- a/database_cleanup/models/purge_columns.py +++ b/database_cleanup/models/purge_columns.py @@ -3,18 +3,19 @@ # pylint: disable=consider-merging-classes-inherited from odoo import _, api, fields, models from odoo.exceptions import UserError + from ..identifier_adapter import IdentifierAdapter class CleanupPurgeLineColumn(models.TransientModel): - _inherit = 'cleanup.purge.line' - _name = 'cleanup.purge.line.column' - _description = 'Purge Column Wizard Lines' + _inherit = "cleanup.purge.line" + _name = "cleanup.purge.line.column" + _description = "Purge Column Wizard Lines" - model_id = fields.Many2one('ir.model', 'Model', required=True, - ondelete='CASCADE') + model_id = fields.Many2one("ir.model", "Model", required=True, ondelete="CASCADE") wizard_id = fields.Many2one( - 'cleanup.purge.wizard.column', 'Purge Wizard', readonly=True) + "cleanup.purge.wizard.column", "Purge Wizard", readonly=True + ) @api.multi def purge(self): @@ -24,8 +25,9 @@ class CleanupPurgeLineColumn(models.TransientModel): if self: objs = self else: - objs = self.env['cleanup.purge.line.column']\ - .browse(self._context.get('active_ids')) + objs = self.env["cleanup.purge.line.column"].browse( + self._context.get("active_ids") + ) for line in objs: if line.purged: continue @@ -34,24 +36,23 @@ class CleanupPurgeLineColumn(models.TransientModel): # Inheritance such as stock.picking.in from stock.picking # can lead to double attempts at removal self.env.cr.execute( - 'SELECT count(attname) FROM pg_attribute ' - 'WHERE attrelid = ' - '( SELECT oid FROM pg_class WHERE relname = %s ) ' - 'AND attname = %s', - (model_pool._table, line.name)) + "SELECT count(attname) FROM pg_attribute " + "WHERE attrelid = " + "( SELECT oid FROM pg_class WHERE relname = %s ) " + "AND attname = %s", + (model_pool._table, line.name), + ) if not self.env.cr.fetchone()[0]: continue self.logger.info( - 'Dropping column %s from table %s', - line.name, model_pool._table) + "Dropping column %s from table %s", line.name, model_pool._table + ) self.env.cr.execute( - 'ALTER TABLE %s DROP COLUMN %s', - ( - IdentifierAdapter(model_pool._table), - IdentifierAdapter(line.name) - )) - line.write({'purged': True}) + "ALTER TABLE %s DROP COLUMN %s", + (IdentifierAdapter(model_pool._table), IdentifierAdapter(line.name)), + ) + line.write({"purged": True}) # we need this commit because the ORM will deadlock if # we still have a pending transaction self.env.cr.commit() # pylint: disable=invalid-commit @@ -59,15 +60,15 @@ class CleanupPurgeLineColumn(models.TransientModel): class CleanupPurgeWizardColumn(models.TransientModel): - _inherit = 'cleanup.purge.wizard' - _name = 'cleanup.purge.wizard.column' - _description = 'Purge columns' + _inherit = "cleanup.purge.wizard" + _name = "cleanup.purge.wizard.column" + _description = "Purge columns" # List of known columns in use without corresponding fields # Format: {table: [fields]} blacklist = { - 'wkf_instance': ['uid'], # lp:1277899 - 'res_users': ['password', 'password_crypt'], + "wkf_instance": ["uid"], # lp:1277899 + "res_users": ["password", "password_crypt"], } @api.model @@ -77,12 +78,14 @@ class CleanupPurgeWizardColumn(models.TransientModel): Iterate on the database columns to identify columns of fields which have been removed """ - columns = list(set([ - column.name - for model_pool in model_pools - for column in model_pool._fields.values() - if not (column.compute is not None and not column.store) - ])) + columns = list( + { + column.name + for model_pool in model_pools + for column in model_pool._fields.values() + if not (column.compute is not None and not column.store) + } + ) columns += models.MAGIC_COLUMNS columns += self.blacklist.get(model_pools[0]._table, []) @@ -92,7 +95,8 @@ class CleanupPurgeWizardColumn(models.TransientModel): "AND pg_catalog.format_type(a.atttypid, a.atttypmod) " "NOT IN ('cid', 'tid', 'oid', 'xid') " "AND a.attname NOT IN %s", - (model_pools[0]._table, tuple(columns))) + (model_pools[0]._table, tuple(columns)), + ) return [column for column, in self.env.cr.fetchall()] @api.model @@ -109,24 +113,23 @@ class CleanupPurgeWizardColumn(models.TransientModel): # mapping of tables to tuples (model id, [pool1, pool2, ...]) table2model = {} - for model in self.env['ir.model'].search([]): + for model in self.env["ir.model"].search([]): if model.model not in self.env: continue model_pool = self.env[model.model] if not model_pool._auto: continue - table2model.setdefault( - model_pool._table, (model.id, []) - )[1].append(model_pool) + table2model.setdefault(model_pool._table, (model.id, []))[1].append( + model_pool + ) for table, model_spec in table2model.items(): for column in self.get_orphaned_columns(model_spec[1]): - res.append((0, 0, { - 'name': column, - 'model_id': model_spec[0]})) + res.append((0, 0, {"name": column, "model_id": model_spec[0]})) if not res: - raise UserError(_('No orphaned columns found')) + raise UserError(_("No orphaned columns found")) return res purge_line_ids = fields.One2many( - 'cleanup.purge.line.column', 'wizard_id', 'Columns to purge') + "cleanup.purge.line.column", "wizard_id", "Columns to purge" + ) diff --git a/database_cleanup/models/purge_data.py b/database_cleanup/models/purge_data.py index efe224a59..e25dc79f1 100644 --- a/database_cleanup/models/purge_data.py +++ b/database_cleanup/models/purge_data.py @@ -2,16 +2,18 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import _, api, fields, models from odoo.exceptions import UserError + from ..identifier_adapter import IdentifierAdapter class CleanupPurgeLineData(models.TransientModel): - _inherit = 'cleanup.purge.line' - _name = 'cleanup.purge.line.data' + _inherit = "cleanup.purge.line" + _name = "cleanup.purge.line.data" - data_id = fields.Many2one('ir.model.data', 'Data entry') + data_id = fields.Many2one("ir.model.data", "Data entry") wizard_id = fields.Many2one( - 'cleanup.purge.wizard.data', 'Purge Wizard', readonly=True) + "cleanup.purge.wizard.data", "Purge Wizard", readonly=True + ) @api.multi def purge(self): @@ -19,18 +21,19 @@ class CleanupPurgeLineData(models.TransientModel): if self: objs = self else: - objs = self.env['cleanup.purge.line.data']\ - .browse(self._context.get('active_ids')) + objs = self.env["cleanup.purge.line.data"].browse( + self._context.get("active_ids") + ) to_unlink = objs.filtered(lambda x: not x.purged and x.data_id) - self.logger.info('Purging data entries: %s', to_unlink.mapped('name')) - to_unlink.mapped('data_id').unlink() - return to_unlink.write({'purged': True}) + self.logger.info("Purging data entries: %s", to_unlink.mapped("name")) + to_unlink.mapped("data_id").unlink() + return to_unlink.write({"purged": True}) class CleanupPurgeWizardData(models.TransientModel): - _inherit = 'cleanup.purge.wizard' - _name = 'cleanup.purge.wizard.data' - _description = 'Purge data' + _inherit = "cleanup.purge.wizard" + _name = "cleanup.purge.wizard.data" + _description = "Purge data" @api.model def find(self): @@ -41,7 +44,7 @@ class CleanupPurgeWizardData(models.TransientModel): data_ids = [] unknown_models = [] self.env.cr.execute("""SELECT DISTINCT(model) FROM ir_model_data""") - for model, in self.env.cr.fetchall(): + for (model,) in self.env.cr.fetchall(): if not model: continue if model not in self.env: @@ -54,19 +57,35 @@ class CleanupPurgeWizardData(models.TransientModel): AND res_id IS NOT NULL AND NOT EXISTS ( SELECT id FROM %s WHERE id=ir_model_data.res_id) - """, (model, IdentifierAdapter(self.env[model]._table))) + """, + (model, IdentifierAdapter(self.env[model]._table)), + ) data_ids.extend(data_row for data_row, in self.env.cr.fetchall()) - data_ids += self.env['ir.model.data'].search([ - ('model', 'in', unknown_models), - ]).ids - for data in self.env['ir.model.data'].browse(data_ids): - res.append((0, 0, { - 'data_id': data.id, - 'name': "%s.%s, object of type %s" % ( - data.module, data.name, data.model)})) + data_ids += ( + self.env["ir.model.data"] + .search( + [ + ("model", "in", unknown_models), + ] + ) + .ids + ) + for data in self.env["ir.model.data"].browse(data_ids): + res.append( + ( + 0, + 0, + { + "data_id": data.id, + "name": "%s.%s, object of type %s" + % (data.module, data.name, data.model), + }, + ) + ) if not res: - raise UserError(_('No orphaned data entries found')) + raise UserError(_("No orphaned data entries found")) return res purge_line_ids = fields.One2many( - 'cleanup.purge.line.data', 'wizard_id', 'Data to purge') + "cleanup.purge.line.data", "wizard_id", "Data to purge" + ) diff --git a/database_cleanup/models/purge_menus.py b/database_cleanup/models/purge_menus.py index b74366161..de41cdccf 100644 --- a/database_cleanup/models/purge_menus.py +++ b/database_cleanup/models/purge_menus.py @@ -6,12 +6,13 @@ from odoo.exceptions import UserError class CleanupPurgeLineMenu(models.TransientModel): - _inherit = 'cleanup.purge.line' - _name = 'cleanup.purge.line.menu' + _inherit = "cleanup.purge.line" + _name = "cleanup.purge.line.menu" wizard_id = fields.Many2one( - 'cleanup.purge.wizard.menu', 'Purge Wizard', readonly=True) - menu_id = fields.Many2one('ir.ui.menu', 'Menu entry') + "cleanup.purge.wizard.menu", "Purge Wizard", readonly=True + ) + menu_id = fields.Many2one("ir.ui.menu", "Menu entry") @api.multi def purge(self): @@ -19,18 +20,19 @@ class CleanupPurgeLineMenu(models.TransientModel): if self: objs = self else: - objs = self.env['cleanup.purge.line.menu']\ - .browse(self._context.get('active_ids')) + objs = self.env["cleanup.purge.line.menu"].browse( + self._context.get("active_ids") + ) to_unlink = objs.filtered(lambda x: not x.purged and x.menu_id) - self.logger.info('Purging menu entries: %s', to_unlink.mapped('name')) - to_unlink.mapped('menu_id').unlink() - return to_unlink.write({'purged': True}) + self.logger.info("Purging menu entries: %s", to_unlink.mapped("name")) + to_unlink.mapped("menu_id").unlink() + return to_unlink.write({"purged": True}) class CleanupPurgeWizardMenu(models.TransientModel): - _inherit = 'cleanup.purge.wizard' - _name = 'cleanup.purge.wizard.menu' - _description = 'Purge menus' + _inherit = "cleanup.purge.wizard" + _name = "cleanup.purge.wizard.menu" + _description = "Purge menus" @api.model def find(self): @@ -38,21 +40,30 @@ class CleanupPurgeWizardMenu(models.TransientModel): Search for models that cannot be instantiated. """ res = [] - for menu in self.env['ir.ui.menu'].with_context(active_test=False)\ - .search([('action', '!=', False)]): - if menu.action.type != 'ir.actions.act_window': + for menu in ( + self.env["ir.ui.menu"] + .with_context(active_test=False) + .search([("action", "!=", False)]) + ): + if menu.action.type != "ir.actions.act_window": continue - if (menu.action.res_model and menu.action.res_model not in - self.env) or \ - (menu.action.src_model and menu.action.src_model not in - self.env): - res.append((0, 0, { - 'name': menu.complete_name, - 'menu_id': menu.id, - })) + if (menu.action.res_model and menu.action.res_model not in self.env) or ( + menu.action.src_model and menu.action.src_model not in self.env + ): + res.append( + ( + 0, + 0, + { + "name": menu.complete_name, + "menu_id": menu.id, + }, + ) + ) if not res: - raise UserError(_('No dangling menu entries found')) + raise UserError(_("No dangling menu entries found")) return res purge_line_ids = fields.One2many( - 'cleanup.purge.line.menu', 'wizard_id', 'Menus to purge') + "cleanup.purge.line.menu", "wizard_id", "Menus to purge" + ) diff --git a/database_cleanup/models/purge_models.py b/database_cleanup/models/purge_models.py index b2c40b93d..f20f5dfc2 100644 --- a/database_cleanup/models/purge_models.py +++ b/database_cleanup/models/purge_models.py @@ -1,13 +1,14 @@ # Copyright 2014-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # pylint: disable=consider-merging-classes-inherited -from odoo import _, api, models, fields +from odoo import _, api, fields, models from odoo.exceptions import UserError + from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG class IrModel(models.Model): - _inherit = 'ir.model' + _inherit = "ir.model" def _drop_table(self): """this function crashes for undefined models""" @@ -22,7 +23,7 @@ class IrModel(models.Model): class IrModelFields(models.Model): - _inherit = 'ir.model.fields' + _inherit = "ir.model.fields" @api.multi def _prepare_update(self): @@ -32,12 +33,13 @@ class IrModelFields(models.Model): class CleanupPurgeLineModel(models.TransientModel): - _inherit = 'cleanup.purge.line' - _name = 'cleanup.purge.line.model' - _description = 'Purge models' + _inherit = "cleanup.purge.line" + _name = "cleanup.purge.line.model" + _description = "Purge models" wizard_id = fields.Many2one( - 'cleanup.purge.wizard.model', 'Purge Wizard', readonly=True) + "cleanup.purge.wizard.model", "Purge Wizard", readonly=True + ) @api.multi def purge(self): @@ -46,36 +48,45 @@ class CleanupPurgeLineModel(models.TransientModel): """ context_flags = { MODULE_UNINSTALL_FLAG: True, - 'purge': True, + "purge": True, } if self: objs = self else: - objs = self.env['cleanup.purge.line.model']\ - .browse(self._context.get('active_ids')) + objs = self.env["cleanup.purge.line.model"].browse( + self._context.get("active_ids") + ) for line in objs: self.env.cr.execute( - "SELECT id, model from ir_model WHERE model = %s", - (line.name,)) + "SELECT id, model from ir_model WHERE model = %s", (line.name,) + ) row = self.env.cr.fetchone() if not row: continue - self.logger.info('Purging model %s', row[1]) - attachments = self.env['ir.attachment'].search([ - ('res_model', '=', line.name) - ]) + self.logger.info("Purging model %s", row[1]) + attachments = self.env["ir.attachment"].search( + [("res_model", "=", line.name)] + ) if attachments: self.env.cr.execute( - "UPDATE ir_attachment SET res_model = NULL " - "WHERE id in %s", - (tuple(attachments.ids), )) - self.env['ir.model.constraint'].search([ - ('model', '=', line.name), - ]).unlink() - relations = self.env['ir.model.fields'].search([ - ('relation', '=', row[1]), - ]).with_context(**context_flags) + "UPDATE ir_attachment SET res_model = NULL " "WHERE id in %s", + (tuple(attachments.ids),), + ) + self.env["ir.model.constraint"].search( + [ + ("model", "=", line.name), + ] + ).unlink() + relations = ( + self.env["ir.model.fields"] + .search( + [ + ("relation", "=", row[1]), + ] + ) + .with_context(**context_flags) + ) for relation in relations: try: # Fails if the model on the target side @@ -85,19 +96,18 @@ class CleanupPurgeLineModel(models.TransientModel): pass except AttributeError: pass - self.env['ir.model.relation'].search([ - ('model', '=', line.name) - ]).with_context(**context_flags).unlink() - self.env['ir.model'].browse([row[0]])\ - .with_context(**context_flags).unlink() - line.write({'purged': True}) + self.env["ir.model.relation"].search( + [("model", "=", line.name)] + ).with_context(**context_flags).unlink() + self.env["ir.model"].browse([row[0]]).with_context(**context_flags).unlink() + line.write({"purged": True}) return True class CleanupPurgeWizardModel(models.TransientModel): - _inherit = 'cleanup.purge.wizard' - _name = 'cleanup.purge.wizard.model' - _description = 'Purge models' + _inherit = "cleanup.purge.wizard" + _name = "cleanup.purge.wizard.model" + _description = "Purge models" @api.model def find(self): @@ -106,12 +116,13 @@ class CleanupPurgeWizardModel(models.TransientModel): """ res = [] self.env.cr.execute("SELECT model from ir_model") - for model, in self.env.cr.fetchall(): + for (model,) in self.env.cr.fetchall(): if model not in self.env: - res.append((0, 0, {'name': model})) + res.append((0, 0, {"name": model})) if not res: - raise UserError(_('No orphaned models found')) + raise UserError(_("No orphaned models found")) return res purge_line_ids = fields.One2many( - 'cleanup.purge.line.model', 'wizard_id', 'Models to purge') + "cleanup.purge.line.model", "wizard_id", "Models to purge" + ) diff --git a/database_cleanup/models/purge_modules.py b/database_cleanup/models/purge_modules.py index 0cb799d22..278badd5f 100644 --- a/database_cleanup/models/purge_modules.py +++ b/database_cleanup/models/purge_modules.py @@ -4,35 +4,39 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError from odoo.modules.module import get_module_path + from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG class IrModelData(models.Model): - _inherit = 'ir.model.data' + _inherit = "ir.model.data" @api.model def _module_data_uninstall(self, modules_to_remove): """this function crashes for xmlids on undefined models or fields referring to undefined models""" - for this in self.search([('module', 'in', modules_to_remove)]): - if this.model == 'ir.model.fields': - field = self.env[this.model].with_context( - **{MODULE_UNINSTALL_FLAG: True}).browse(this.res_id) + for this in self.search([("module", "in", modules_to_remove)]): + if this.model == "ir.model.fields": + field = ( + self.env[this.model] + .with_context(**{MODULE_UNINSTALL_FLAG: True}) + .browse(this.res_id) + ) if not field.exists() or field.model not in self.env: this.unlink() continue if this.model not in self.env: this.unlink() - return super(IrModelData, self)._module_data_uninstall( - modules_to_remove) + return super(IrModelData, self)._module_data_uninstall(modules_to_remove) class CleanupPurgeLineModule(models.TransientModel): - _inherit = 'cleanup.purge.line' - _name = 'cleanup.purge.line.module' + _inherit = "cleanup.purge.line" + _name = "cleanup.purge.line.module" wizard_id = fields.Many2one( - 'cleanup.purge.wizard.module', 'Purge Wizard', readonly=True) + "cleanup.purge.wizard.module", "Purge Wizard", readonly=True + ) @api.multi def purge(self): @@ -40,48 +44,46 @@ class CleanupPurgeLineModule(models.TransientModel): Uninstall modules upon manual confirmation, then reload the database. """ - module_names = self.filtered(lambda x: not x.purged).mapped('name') - modules = self.env['ir.module.module'].search([ - ('name', 'in', module_names) - ]) + module_names = self.filtered(lambda x: not x.purged).mapped("name") + modules = self.env["ir.module.module"].search([("name", "in", module_names)]) if not modules: return True - self.logger.info('Purging modules %s', ', '.join(module_names)) + self.logger.info("Purging modules %s", ", ".join(module_names)) modules.filtered( - lambda x: x.state not in ('uninstallable', 'uninstalled') + lambda x: x.state not in ("uninstallable", "uninstalled") ).button_immediate_uninstall() modules.refresh() modules.unlink() - return self.write({'purged': True}) + return self.write({"purged": True}) class CleanupPurgeWizardModule(models.TransientModel): - _inherit = 'cleanup.purge.wizard' - _name = 'cleanup.purge.wizard.module' - _description = 'Purge modules' + _inherit = "cleanup.purge.wizard" + _name = "cleanup.purge.wizard.module" + _description = "Purge modules" @api.model def find(self): res = [] - IrModule = self.env['ir.module.module'] + IrModule = self.env["ir.module.module"] for module in IrModule.search( - [ - ('to_buy', '=', False), - ('name', '!=', 'studio_customization') - ] + [("to_buy", "=", False), ("name", "!=", "studio_customization")] ): if get_module_path(module.name, display_warning=False): continue - if module.state == 'uninstalled': - self.env['cleanup.purge.line.module'].create({ - 'name': module.name, - }).purge() + if module.state == "uninstalled": + self.env["cleanup.purge.line.module"].create( + { + "name": module.name, + } + ).purge() continue - res.append((0, 0, {'name': module.name})) + res.append((0, 0, {"name": module.name})) if not res: - raise UserError(_('No modules found to purge')) + raise UserError(_("No modules found to purge")) return res purge_line_ids = fields.One2many( - 'cleanup.purge.line.module', 'wizard_id', 'Modules to purge') + "cleanup.purge.line.module", "wizard_id", "Modules to purge" + ) diff --git a/database_cleanup/models/purge_properties.py b/database_cleanup/models/purge_properties.py index 61d7dd9f7..b79e8fec8 100644 --- a/database_cleanup/models/purge_properties.py +++ b/database_cleanup/models/purge_properties.py @@ -1,7 +1,8 @@ # Copyright 2017 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # pylint: disable=consider-merging-classes-inherited -from odoo import api, models, fields +from odoo import api, fields, models + REASON_DUPLICATE = 1 REASON_DEFAULT = 2 REASON_DEFAULT_FALSE = 3 @@ -9,31 +10,34 @@ REASON_UNKNOWN_MODEL = 4 class CleanupPurgeLineProperty(models.TransientModel): - _inherit = 'cleanup.purge.line' - _name = 'cleanup.purge.line.property' - _description = 'Purge properties' + _inherit = "cleanup.purge.line" + _name = "cleanup.purge.line.property" + _description = "Purge properties" wizard_id = fields.Many2one( - 'cleanup.purge.wizard.property', 'Purge Wizard', readonly=True) - property_id = fields.Many2one('ir.property') - reason = fields.Selection([ - (REASON_DUPLICATE, 'Duplicated property'), - (REASON_DEFAULT, 'Same value as default'), - (REASON_DEFAULT_FALSE, 'Empty default property'), - (REASON_UNKNOWN_MODEL, 'Unknown model'), - ]) + "cleanup.purge.wizard.property", "Purge Wizard", readonly=True + ) + property_id = fields.Many2one("ir.property") + reason = fields.Selection( + [ + (REASON_DUPLICATE, "Duplicated property"), + (REASON_DEFAULT, "Same value as default"), + (REASON_DEFAULT_FALSE, "Empty default property"), + (REASON_UNKNOWN_MODEL, "Unknown model"), + ] + ) @api.multi def purge(self): """Delete properties""" - self.write({'purged': True}) - return self.mapped('property_id').unlink() + self.write({"purged": True}) + return self.mapped("property_id").unlink() class CleanupPurgeWizardProperty(models.TransientModel): - _inherit = 'cleanup.purge.wizard' - _name = 'cleanup.purge.wizard.property' - _description = 'Purge properties' + _inherit = "cleanup.purge.wizard" + _name = "cleanup.purge.wizard.property" + _description = "Purge properties" @api.model def find(self): @@ -41,96 +45,118 @@ class CleanupPurgeWizardProperty(models.TransientModel): Search property records which are duplicated or the same as the default """ result = [] - default_properties = self.env['ir.property'].search([ - ('res_id', '=', False), - ]) + default_properties = self.env["ir.property"].search( + [ + ("res_id", "=", False), + ] + ) handled_field_ids = [] for prop in default_properties: value = None try: value = prop.get_by_record() except KeyError: - result.append({ - 'name': '%s@%s: %s' % ( - prop.name, prop.res_id, value, - ), - 'property_id': prop.id, - 'reason': REASON_UNKNOWN_MODEL, - }) + result.append( + { + "name": "%s@%s: %s" + % ( + prop.name, + prop.res_id, + value, + ), + "property_id": prop.id, + "reason": REASON_UNKNOWN_MODEL, + } + ) continue if not value: - result.append({ - 'name': '%s@%s: %s' % ( - prop.name, prop.res_id, value, - ), - 'property_id': prop.id, - 'reason': REASON_DEFAULT_FALSE, - }) + result.append( + { + "name": "%s@%s: %s" + % ( + prop.name, + prop.res_id, + value, + ), + "property_id": prop.id, + "reason": REASON_DEFAULT_FALSE, + } + ) continue if prop.fields_id.id in handled_field_ids: continue domain = [ - ('id', '!=', prop.id), - ('fields_id', '=', prop.fields_id.id), + ("id", "!=", prop.id), + ("fields_id", "=", prop.fields_id.id), # =? explicitly tests for None or False, not falsyness - ('value_float', '=?', prop.value_float or False), - ('value_integer', '=?', prop.value_integer or False), - ('value_text', '=?', prop.value_text or False), - ('value_binary', '=?', prop.value_binary or False), - ('value_reference', '=?', prop.value_reference or False), - ('value_datetime', '=?', prop.value_datetime or False), + ("value_float", "=?", prop.value_float or False), + ("value_integer", "=?", prop.value_integer or False), + ("value_text", "=?", prop.value_text or False), + ("value_binary", "=?", prop.value_binary or False), + ("value_reference", "=?", prop.value_reference or False), + ("value_datetime", "=?", prop.value_datetime or False), ] if prop.company_id: - domain.append(('company_id', '=', prop.company_id.id)) + domain.append(("company_id", "=", prop.company_id.id)) else: - domain.extend([ - '|', - ('company_id', '=', False), - ( - 'company_id', 'in', self.env['res.company'].search([ - ( - 'id', 'not in', default_properties.filtered( - lambda x: x.company_id and - x.fields_id == prop.fields_id - ).ids, + domain.extend( + [ + "|", + ("company_id", "=", False), + ( + "company_id", + "in", + self.env["res.company"] + .search( + [ + ( + "id", + "not in", + default_properties.filtered( + lambda x: x.company_id + and x.fields_id == prop.fields_id + ).ids, + ) + ] ) - ]).ids - ), - ]) + .ids, + ), + ] + ) - for redundant_property in self.env['ir.property'].search(domain): - result.append({ - 'name': '%s@%s: %s' % ( - prop.name, redundant_property.res_id, - prop.get_by_record() - ), - 'property_id': redundant_property.id, - 'reason': REASON_DEFAULT, - }) + for redundant_property in self.env["ir.property"].search(domain): + result.append( + { + "name": "%s@%s: %s" + % (prop.name, redundant_property.res_id, prop.get_by_record()), + "property_id": redundant_property.id, + "reason": REASON_DEFAULT, + } + ) handled_field_ids.append(prop.fields_id.id) self.env.cr.execute( - ''' + """ with grouped_properties(ids, cnt) as ( select array_agg(id), count(*) from ir_property group by res_id, company_id, fields_id ) select ids from grouped_properties where cnt > 1 - ''' + """ ) - for ids, in self.env.cr.fetchall(): + for (ids,) in self.env.cr.fetchall(): # odoo uses the first property found by search - for prop in self.env['ir.property'].search([ - ('id', 'in', ids) - ])[1:]: - result.append({ - 'name': '%s@%s: %s' % ( - prop.name, prop.res_id, prop.get_by_record() - ), - 'property_id': prop.id, - 'reason': REASON_DUPLICATE, - }) + for prop in self.env["ir.property"].search([("id", "in", ids)])[1:]: + result.append( + { + "name": "%s@%s: %s" + % (prop.name, prop.res_id, prop.get_by_record()), + "property_id": prop.id, + "reason": REASON_DUPLICATE, + } + ) return result purge_line_ids = fields.One2many( - 'cleanup.purge.line.property', 'wizard_id', 'Properties to purge') + "cleanup.purge.line.property", "wizard_id", "Properties to purge" + ) diff --git a/database_cleanup/models/purge_tables.py b/database_cleanup/models/purge_tables.py index e9873af8f..58086b67d 100644 --- a/database_cleanup/models/purge_tables.py +++ b/database_cleanup/models/purge_tables.py @@ -1,18 +1,20 @@ # Copyright 2014-2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # pylint: disable=consider-merging-classes-inherited -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import UserError + from ..identifier_adapter import IdentifierAdapter class CleanupPurgeLineTable(models.TransientModel): - _inherit = 'cleanup.purge.line' - _name = 'cleanup.purge.line.table' - _description = 'Purge tables wizard lines' + _inherit = "cleanup.purge.line" + _name = "cleanup.purge.line.table" + _description = "Purge tables wizard lines" wizard_id = fields.Many2one( - 'cleanup.purge.wizard.table', 'Purge Wizard', readonly=True) + "cleanup.purge.wizard.table", "Purge Wizard", readonly=True + ) @api.multi def purge(self): @@ -22,9 +24,10 @@ class CleanupPurgeLineTable(models.TransientModel): if self: objs = self else: - objs = self.env['cleanup.purge.line.table']\ - .browse(self._context.get('active_ids')) - tables = objs.mapped('name') + objs = self.env["cleanup.purge.line.table"].browse( + self._context.get("active_ids") + ) + tables = objs.mapped("name") for line in objs: if line.purged: continue @@ -49,32 +52,35 @@ class CleanupPurgeLineTable(models.TransientModel): WHERE af.attnum = confkey AND af.attrelid = confrelid AND a.attnum = conkey AND a.attrelid = conrelid AND confrelid::regclass = '%s'::regclass; - """, (IdentifierAdapter(line.name, quote=False),)) + """, + (IdentifierAdapter(line.name, quote=False),), + ) for constraint in self.env.cr.fetchall(): if constraint[3] in tables: self.logger.info( - 'Dropping constraint %s on table %s (to be dropped)', - constraint[0], constraint[3]) + "Dropping constraint %s on table %s (to be dropped)", + constraint[0], + constraint[3], + ) self.env.cr.execute( "ALTER TABLE %s DROP CONSTRAINT %s", ( IdentifierAdapter(constraint[3]), - IdentifierAdapter(constraint[0]) - )) + IdentifierAdapter(constraint[0]), + ), + ) - self.logger.info( - 'Dropping table %s', line.name) - self.env.cr.execute( - "DROP TABLE %s", (IdentifierAdapter(line.name),)) - line.write({'purged': True}) + self.logger.info("Dropping table %s", line.name) + self.env.cr.execute("DROP TABLE %s", (IdentifierAdapter(line.name),)) + line.write({"purged": True}) return True class CleanupPurgeWizardTable(models.TransientModel): - _inherit = 'cleanup.purge.wizard' - _name = 'cleanup.purge.wizard.table' - _description = 'Purge tables' + _inherit = "cleanup.purge.wizard" + _name = "cleanup.purge.wizard.table" + _description = "Purge tables" @api.model def find(self): @@ -83,7 +89,7 @@ class CleanupPurgeWizardTable(models.TransientModel): Ignore views for now. """ known_tables = [] - for model in self.env['ir.model'].search([]): + for model in self.env["ir.model"].search([]): if model.model not in self.env: continue model_pool = self.env[model.model] @@ -91,8 +97,8 @@ class CleanupPurgeWizardTable(models.TransientModel): known_tables += [ column.relation for column in model_pool._fields.values() - if column.type == 'many2many' and - (column.compute is None or column.store) + if column.type == "many2many" + and (column.compute is None or column.store) and column.relation ] @@ -100,12 +106,15 @@ class CleanupPurgeWizardTable(models.TransientModel): """ SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE' - AND table_name NOT IN %s""", (tuple(known_tables),)) + AND table_name NOT IN %s""", + (tuple(known_tables),), + ) - res = [(0, 0, {'name': row[0]}) for row in self.env.cr.fetchall()] + res = [(0, 0, {"name": row[0]}) for row in self.env.cr.fetchall()] if not res: - raise UserError(_('No orphaned tables found')) + raise UserError(_("No orphaned tables found")) return res purge_line_ids = fields.One2many( - 'cleanup.purge.line.table', 'wizard_id', 'Tables to purge') + "cleanup.purge.line.table", "wizard_id", "Tables to purge" + ) diff --git a/database_cleanup/models/purge_wizard.py b/database_cleanup/models/purge_wizard.py index 361615512..eb07fd47e 100644 --- a/database_cleanup/models/purge_wizard.py +++ b/database_cleanup/models/purge_wizard.py @@ -3,21 +3,23 @@ # pylint: disable=consider-merging-classes-inherited import logging + from odoo import _, api, fields, models from odoo.exceptions import AccessDenied class CleanupPurgeLine(models.AbstractModel): """ Abstract base class for the purge wizard lines """ - _name = 'cleanup.purge.line' - _order = 'name' - _description = 'Purge Column Abstract Wizard' - name = fields.Char('Name', readonly=True) - purged = fields.Boolean('Purged', readonly=True) - wizard_id = fields.Many2one('cleanup.purge.wizard') + _name = "cleanup.purge.line" + _order = "name" + _description = "Purge Column Abstract Wizard" - logger = logging.getLogger('odoo.addons.database_cleanup') + name = fields.Char("Name", readonly=True) + purged = fields.Boolean("Purged", readonly=True) + wizard_id = fields.Many2one("cleanup.purge.wizard") + + logger = logging.getLogger("odoo.addons.database_cleanup") @api.multi def purge(self): @@ -26,22 +28,22 @@ class CleanupPurgeLine(models.AbstractModel): @api.model def create(self, values): # make sure the user trying this is actually supposed to do it - if self.env.ref( - 'base.group_erp_manager') not in self.env.user.groups_id: + if self.env.ref("base.group_erp_manager") not in self.env.user.groups_id: raise AccessDenied return super(CleanupPurgeLine, self).create(values) class PurgeWizard(models.AbstractModel): """ Abstract base class for the purge wizards """ - _name = 'cleanup.purge.wizard' - _description = 'Purge stuff' + + _name = "cleanup.purge.wizard" + _description = "Purge stuff" @api.model def default_get(self, fields_list): res = super(PurgeWizard, self).default_get(fields_list) - if 'purge_line_ids' in fields_list: - res['purge_line_ids'] = self.find() + if "purge_line_ids" in fields_list: + res["purge_line_ids"] = self.find() return res @api.multi @@ -50,47 +52,43 @@ class PurgeWizard(models.AbstractModel): @api.multi def purge_all(self): - self.mapped('purge_line_ids').purge() + self.mapped("purge_line_ids").purge() return True @api.model def get_wizard_action(self): wizard = self.create({}) return { - 'type': 'ir.actions.act_window', - 'name': wizard.display_name, - 'views': [(False, 'form')], - 'res_model': self._name, - 'res_id': wizard.id, - 'flags': { - 'action_buttons': False, - 'sidebar': False, + "type": "ir.actions.act_window", + "name": wizard.display_name, + "views": [(False, "form")], + "res_model": self._name, + "res_id": wizard.id, + "flags": { + "action_buttons": False, + "sidebar": False, }, } @api.multi def select_lines(self): return { - 'type': 'ir.actions.act_window', - 'name': _('Select lines to purge'), - 'views': [(False, 'tree'), (False, 'form')], - 'res_model': self._fields['purge_line_ids'].comodel_name, - 'domain': [('wizard_id', 'in', self.ids)], + "type": "ir.actions.act_window", + "name": _("Select lines to purge"), + "views": [(False, "tree"), (False, "form")], + "res_model": self._fields["purge_line_ids"].comodel_name, + "domain": [("wizard_id", "in", self.ids)], } @api.multi def name_get(self): - return [ - (this.id, self._description) - for this in self - ] + return [(this.id, self._description) for this in self] @api.model def create(self, values): # make sure the user trying this is actually supposed to do it - if self.env.ref( - 'base.group_erp_manager') not in self.env.user.groups_id: + if self.env.ref("base.group_erp_manager") not in self.env.user.groups_id: raise AccessDenied return super(PurgeWizard, self).create(values) - purge_line_ids = fields.One2many('cleanup.purge.line', 'wizard_id') + purge_line_ids = fields.One2many("cleanup.purge.line", "wizard_id") diff --git a/database_cleanup/tests/test_database_cleanup.py b/database_cleanup/tests/test_database_cleanup.py index 9942efe6f..e9ae57657 100644 --- a/database_cleanup/tests/test_database_cleanup.py +++ b/database_cleanup/tests/test_database_cleanup.py @@ -1,9 +1,10 @@ # Copyright 2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from psycopg2 import ProgrammingError + from odoo.modules.registry import Registry -from odoo.tools import config, mute_logger from odoo.tests.common import TransactionCase, at_install, post_install +from odoo.tools import config, mute_logger # Use post_install to get all models loaded more info: odoo/odoo#13458 @@ -15,103 +16,129 @@ class TestDatabaseCleanup(TransactionCase): self.module = None self.model = None # Create one property for tests - self.env['ir.property'].create({ - 'fields_id': self.env.ref('base.field_res_partner__name').id, - 'type': 'char', - 'value_text': 'My default partner name', - }) + self.env["ir.property"].create( + { + "fields_id": self.env.ref("base.field_res_partner__name").id, + "type": "char", + "value_text": "My default partner name", + } + ) def test_database_cleanup(self): # delete some index and check if our module recreated it - self.env.cr.execute('drop index res_partner_name_index') - create_indexes = self.env['cleanup.create_indexes.wizard'].create({}) + self.env.cr.execute("drop index res_partner_name_index") + create_indexes = self.env["cleanup.create_indexes.wizard"].create({}) create_indexes.purge_all() self.env.cr.execute( - 'select indexname from pg_indexes ' + "select indexname from pg_indexes " "where indexname='res_partner_name_index' and " "tablename='res_partner'" ) self.assertEqual(self.env.cr.rowcount, 1) # duplicate a property - duplicate_property = self.env['ir.property'].search([], limit=1).copy() - purge_property = self.env['cleanup.purge.wizard.property'].create({}) + duplicate_property = self.env["ir.property"].search([], limit=1).copy() + purge_property = self.env["cleanup.purge.wizard.property"].create({}) purge_property.purge_all() self.assertFalse(duplicate_property.exists()) # create an orphaned column self.env.cr.execute( - 'alter table res_partner add column database_cleanup_test int') + "alter table res_partner add column database_cleanup_test int" + ) # We need use a model that is not blocked (Avoid use res.users) - partner_model = self.env['ir.model'].search([ - ('model', '=', 'res.partner')], limit=1) - purge_columns = self.env['cleanup.purge.wizard.column'].create({ - 'purge_line_ids': [(0, 0, { - 'model_id': partner_model.id, 'name': 'database_cleanup_test'} - )]}) + partner_model = self.env["ir.model"].search( + [("model", "=", "res.partner")], limit=1 + ) + purge_columns = self.env["cleanup.purge.wizard.column"].create( + { + "purge_line_ids": [ + ( + 0, + 0, + {"model_id": partner_model.id, "name": "database_cleanup_test"}, + ) + ] + } + ) purge_columns.purge_all() # must be removed by the wizard with self.assertRaises(ProgrammingError): with self.env.registry.cursor() as cr: - with mute_logger('odoo.sql_db'): - cr.execute('select database_cleanup_test from res_partner') + with mute_logger("odoo.sql_db"): + cr.execute("select database_cleanup_test from res_partner") # create a data entry pointing nowhere - self.env.cr.execute('select max(id) + 1 from res_users') - self.env['ir.model.data'].create({ - 'module': 'database_cleanup', - 'name': 'test_no_data_entry', - 'model': 'res.users', - 'res_id': self.env.cr.fetchone()[0], - }) - purge_data = self.env['cleanup.purge.wizard.data'].create({}) + self.env.cr.execute("select max(id) + 1 from res_users") + self.env["ir.model.data"].create( + { + "module": "database_cleanup", + "name": "test_no_data_entry", + "model": "res.users", + "res_id": self.env.cr.fetchone()[0], + } + ) + purge_data = self.env["cleanup.purge.wizard.data"].create({}) purge_data.purge_all() # must be removed by the wizard with self.assertRaises(ValueError): - self.env.ref('database_cleanup.test_no_data_entry') + self.env.ref("database_cleanup.test_no_data_entry") # create a nonexistent model - self.model = self.env['ir.model'].create({ - 'name': 'Database cleanup test model', - 'model': 'x_database.cleanup.test.model', - }) + self.model = self.env["ir.model"].create( + { + "name": "Database cleanup test model", + "model": "x_database.cleanup.test.model", + } + ) self.env.cr.execute( - 'insert into ir_attachment (name, res_model, res_id, type) values ' - "('test attachment', 'database.cleanup.test.model', 42, 'binary')") - self.env.registry.models.pop('x_database.cleanup.test.model') - purge_models = self.env['cleanup.purge.wizard.model'].create({}) + "insert into ir_attachment (name, res_model, res_id, type) values " + "('test attachment', 'database.cleanup.test.model', 42, 'binary')" + ) + self.env.registry.models.pop("x_database.cleanup.test.model") + purge_models = self.env["cleanup.purge.wizard.model"].create({}) purge_models.purge_all() # must be removed by the wizard - self.assertFalse(self.env['ir.model'].search([ - ('model', '=', 'x_database.cleanup.test.model'), - ])) + self.assertFalse( + self.env["ir.model"].search( + [ + ("model", "=", "x_database.cleanup.test.model"), + ] + ) + ) # create a nonexistent module - self.module = self.env['ir.module.module'].create({ - 'name': 'database_cleanup_test', - 'state': 'to upgrade', - }) - purge_modules = self.env['cleanup.purge.wizard.module'].create({}) + self.module = self.env["ir.module.module"].create( + { + "name": "database_cleanup_test", + "state": "to upgrade", + } + ) + purge_modules = self.env["cleanup.purge.wizard.module"].create({}) # this reloads our registry, and we don't want to run tests twice # we also need the original registry for further tests, so save a # reference to it original_registry = Registry.registries[self.env.cr.dbname] - config.options['test_enable'] = False + config.options["test_enable"] = False purge_modules.purge_all() - config.options['test_enable'] = True + config.options["test_enable"] = True # must be removed by the wizard - self.assertFalse(self.env['ir.module.module'].search([ - ('name', '=', 'database_cleanup_test'), - ])) + self.assertFalse( + self.env["ir.module.module"].search( + [ + ("name", "=", "database_cleanup_test"), + ] + ) + ) # reset afterwards Registry.registries[self.env.cr.dbname] = original_registry # create an orphaned table - self.env.cr.execute('create table database_cleanup_test (test int)') - purge_tables = self.env['cleanup.purge.wizard.table'].create({}) + self.env.cr.execute("create table database_cleanup_test (test int)") + purge_tables = self.env["cleanup.purge.wizard.table"].create({}) purge_tables.purge_all() with self.assertRaises(ProgrammingError): with self.env.registry.cursor() as cr: - with mute_logger('odoo.sql_db'): - cr.execute('select * from database_cleanup_test') + with mute_logger("odoo.sql_db"): + cr.execute("select * from database_cleanup_test") def tearDown(self): super(TestDatabaseCleanup, self).tearDown() @@ -120,10 +147,8 @@ class TestDatabaseCleanup(TransactionCase): self.env.cr.rollback() if self.module: cr2.execute( - "DELETE FROM ir_module_module WHERE id=%s", - (self.module.id,)) + "DELETE FROM ir_module_module WHERE id=%s", (self.module.id,) + ) if self.model: - cr2.execute( - "DELETE FROM ir_model WHERE id=%s", - (self.model.id,)) + cr2.execute("DELETE FROM ir_model WHERE id=%s", (self.model.id,)) cr2.commit() diff --git a/database_cleanup/views/create_indexes.xml b/database_cleanup/views/create_indexes.xml index d0aa21485..b8c982c89 100644 --- a/database_cleanup/views/create_indexes.xml +++ b/database_cleanup/views/create_indexes.xml @@ -1,4 +1,4 @@ - + cleanup.create_indexes.wizard @@ -18,8 +18,13 @@ Create missing indexes ir.actions.server code - - action = env.get('cleanup.create_indexes.wizard').get_wizard_action() + + action = env.get('cleanup.create_indexes.wizard').get_wizard_action() @@ -38,8 +43,14 @@ Create ir.actions.server code - + records.purge() - + diff --git a/database_cleanup/views/menu.xml b/database_cleanup/views/menu.xml index fcaebbe71..98e53003c 100644 --- a/database_cleanup/views/menu.xml +++ b/database_cleanup/views/menu.xml @@ -1,66 +1,66 @@ - + Database cleanup - - + + Purge obsolete modules - + Purge obsolete models - + Purge obsolete columns - + Purge obsolete tables - + Purge obsolete data entries - + Purge obsolete menu entries - + Create missing indexes - + Purge obsolete properties - + diff --git a/database_cleanup/views/purge_columns.xml b/database_cleanup/views/purge_columns.xml index e8c40565d..efc5a7ae7 100644 --- a/database_cleanup/views/purge_columns.xml +++ b/database_cleanup/views/purge_columns.xml @@ -1,4 +1,4 @@ - + cleanup.purge.wizard.column @@ -15,7 +15,10 @@ Purge columns ir.actions.server code - + action = env.get('cleanup.purge.wizard.column').get_wizard_action() @@ -38,6 +41,9 @@ code records.purge() - + diff --git a/database_cleanup/views/purge_data.xml b/database_cleanup/views/purge_data.xml index 42cd2707b..57dcdbf57 100644 --- a/database_cleanup/views/purge_data.xml +++ b/database_cleanup/views/purge_data.xml @@ -1,4 +1,4 @@ - + cleanup.purge.wizard.data @@ -38,6 +38,9 @@ code records.purge() - + diff --git a/database_cleanup/views/purge_menus.xml b/database_cleanup/views/purge_menus.xml index 09e6582fa..8b6286c0f 100644 --- a/database_cleanup/views/purge_menus.xml +++ b/database_cleanup/views/purge_menus.xml @@ -1,11 +1,11 @@ - + cleanup.purge.wizard.menu primary - + @@ -34,6 +34,9 @@ code records.purge() - + diff --git a/database_cleanup/views/purge_models.xml b/database_cleanup/views/purge_models.xml index a72e18977..37cd3b97a 100644 --- a/database_cleanup/views/purge_models.xml +++ b/database_cleanup/views/purge_models.xml @@ -1,4 +1,4 @@ - + cleanup.purge.wizard.model @@ -13,7 +13,10 @@ Purge models ir.actions.server code - + action = env.get('cleanup.purge.wizard.model').get_wizard_action() @@ -34,6 +37,9 @@ code records.purge() - + diff --git a/database_cleanup/views/purge_modules.xml b/database_cleanup/views/purge_modules.xml index d105c7b75..90c1b4bd3 100644 --- a/database_cleanup/views/purge_modules.xml +++ b/database_cleanup/views/purge_modules.xml @@ -1,4 +1,4 @@ - + cleanup.purge.wizard.module @@ -13,7 +13,10 @@ Purge modules ir.actions.server code - + action = env.get('cleanup.purge.wizard.module').get_wizard_action() @@ -24,7 +27,7 @@ primary - + @@ -34,6 +37,9 @@ code records.purge() - + diff --git a/database_cleanup/views/purge_properties.xml b/database_cleanup/views/purge_properties.xml index ca03cf70a..a21f34dcb 100644 --- a/database_cleanup/views/purge_properties.xml +++ b/database_cleanup/views/purge_properties.xml @@ -1,4 +1,4 @@ - + cleanup.purge.wizard.property @@ -13,8 +13,13 @@ Purge properties ir.actions.server code - - action = env.get('cleanup.purge.wizard.property').get_wizard_action() + + action = env.get('cleanup.purge.wizard.property').get_wizard_action() @@ -32,8 +37,14 @@ Purge ir.actions.server code - + records.purge() - + diff --git a/database_cleanup/views/purge_tables.xml b/database_cleanup/views/purge_tables.xml index d255e77c1..f8f3d0d14 100644 --- a/database_cleanup/views/purge_tables.xml +++ b/database_cleanup/views/purge_tables.xml @@ -1,4 +1,4 @@ - + cleanup.purge.wizard.table @@ -13,7 +13,10 @@ Purge tables ir.actions.server code - + action = env.get('cleanup.purge.wizard.table').get_wizard_action() @@ -34,6 +37,9 @@ code records.purge() - + diff --git a/database_cleanup/views/purge_wizard.xml b/database_cleanup/views/purge_wizard.xml index 5f909e335..d0872a4e1 100644 --- a/database_cleanup/views/purge_wizard.xml +++ b/database_cleanup/views/purge_wizard.xml @@ -1,26 +1,38 @@ - + cleanup.purge.wizard
-
Nothing found to clean up.
- +
-
@@ -33,9 +45,13 @@ -