Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7a0afcc
[ADD] Database cleanup module
Jan 28, 2014
8f62ece
remove relations when purging models
Feb 3, 2014
f08a8e1
[FIX] Don't remove uid field from wkf_instance, which is written in
Feb 8, 2014
a0838f3
[CHG] Migration to 8.0
anthony-muschang Dec 11, 2014
e3edc2f
[IMP] hide unnecessary buttons in wizard
hbrunn Apr 28, 2015
687711e
Missing templates and translations added
sysadminmatmoz Aug 11, 2015
40530a9
[ADD] allow to clean up menus
hbrunn Aug 28, 2015
e4340ed
[IMP] allow to select lines to purge in a tree view
hbrunn Jul 17, 2015
113fafd
[ADD] migrate database_cleanup
hbrunn Jun 29, 2016
bcf1570
[RFR] Explicit access rights so that tests can run
StefanRijnhart Aug 9, 2016
1cd2391
[FIX] purge uninstalled uninstallable modules instead of deleting
hbrunn Aug 2, 2016
29a396b
OCA Transbot updated translations from Transifex
oca-transbot Oct 5, 2015
1c7fbff
[IMP] call the button handler to also purge reverse dependencies
hbrunn Sep 15, 2016
c2ca39e
[FIX] don't crash if an xmlid refers to a nonexisting field (#559)
hbrunn Sep 26, 2016
d2b77e9
[FIX] clean database menus was proposing good menus to purge (#562)
JordiBForgeFlow Sep 28, 2016
a6a3f90
fixes #587
florian-dacosta Nov 1, 2016
a7b4ffd
[FIX] database_cleanup: Fix test (#612)
moylop260 Nov 22, 2016
e39d6de
[9.0][FIX] database_cleanup: Isolate build (#719)
lasley Feb 7, 2017
3d29fbe
[ADD] allow creating missing indexes and purging properties (#736)
hbrunn Apr 19, 2017
605ae4b
[MIG] database_cleanup: Migration to version 10.0
eantones Jun 21, 2017
2de5414
[FIX] really uninstall modules and avoid a crash on cached data
hbrunn Aug 1, 2017
f970118
[ADD] [database_cleanup] migrate to 11.0
hbrunn Oct 3, 2017
b321e73
OCA Transbot updated translations from Transifex
oca-transbot Mar 3, 2018
776478d
database_cleanup_fix_runbot_links
fanha99 Jul 20, 2018
8d0a8b4
Global pylint cleanup
simahawk Sep 3, 2018
1118c9e
[FIX] don't destroy values when there are empty default properties
hbrunn Feb 11, 2019
c2d2b8f
[FIX] show the redundant property's res_id, not the default one's
hbrunn Feb 11, 2019
761a09c
[IMP] don't break on properties pointing to unknown models
hbrunn Feb 14, 2019
acd2703
[MIG] database_cleanup: migration to 12.0
mart-e Oct 26, 2018
282886f
[FIX] database_cleanup: exclude password fields
mart-e Apr 8, 2019
8d05d19
[I18N] database_cleanup: reflect changes to en.po
mart-e Apr 16, 2019
3a2f771
[FIX] database_cleanup: filter on many2many fields
mart-e May 6, 2019
d502f72
[FIX] database_cleanup: ignore to_buy modules
mart-e May 9, 2019
efd88c2
[IMP] travis: isolate database_cleanup again
hbrunn Feb 13, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ env:

matrix:
- LINT_CHECK="1"
- TESTS="1" ODOO_REPO="OCA/OCB"
- TESTS="1" ODOO_REPO="OCA/OCB" MAKEPOT="1"
- TESTS="1" ODOO_REPO="OCA/OCB" EXCLUDE="database_cleanup"
- TESTS="1" ODOO_REPO="OCA/OCB" INCLUDE="database_cleanup"
- TESTS="1" ODOO_REPO="odoo/odoo" EXCLUDE="database_cleanup" MAKEPOT="1"
- TESTS="1" ODOO_REPO="odoo/odoo" INCLUDE="database_cleanup" MAKEPOT="1"


install:
- git clone --depth=1 https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools
Expand Down
69 changes: 69 additions & 0 deletions database_cleanup/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3

================
Database cleanup
================

Clean your Odoo database from remnants of modules, models, columns and
tables left by uninstalled modules (prior to 7.0) or a homebrew database
upgrade to a new major version of Odoo.

Caution! This module is potentially harmful and can *easily* destroy the
integrity of your data. Do not use if you are not entirely comfortable
with the technical details of the Odoo data model of *all* the modules
that have ever been installed on your database, and do not purge any module,
model, column or table if you do not know exactly what you are doing.

Usage
=====

After installation of this module, go to the Settings menu -> Technical ->
Database cleanup. This menu is only available to members of the *Access Rights*
group. Go through the modules, models, columns and tables
entries under this menu (in that order) and find out if there is orphaned data
in your database. You can either delete entries by line, or sweep all entries
in one big step (if you are *really* confident).

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/149/11.0

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/database_cleanup/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback.

Credits
=======

Images
------

* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.

Contributors
------------

* Stefan Rijnhart <stefan@opener.amsterdam>
* Holger Brunn <hbrunn@therp.nl>

Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list <mailto:community@mail.odoo.com>`_ or the `appropriate specialized mailinglist <https://odoo-community.org/groups>`_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues.

Maintainer
----------

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

This module is maintained by the OCA.

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.

To contribute to this module, please visit https://odoo-community.org.
3 changes: 3 additions & 0 deletions database_cleanup/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models
23 changes: 23 additions & 0 deletions database_cleanup/__openerp__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'Database cleanup',
'version': '12.0.1.0.0',
'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/create_indexes.xml",
'views/purge_properties.xml',
'views/menu.xml',
],
'installable': True,
}
538 changes: 538 additions & 0 deletions database_cleanup/i18n/am.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/ar.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/bg.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/bs.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/ca.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/cs.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/cs_CZ.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/da.po

Large diffs are not rendered by default.

546 changes: 546 additions & 0 deletions database_cleanup/i18n/database_cleanup.pot

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/de.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/el_GR.po

Large diffs are not rendered by default.

486 changes: 486 additions & 0 deletions database_cleanup/i18n/en.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/en_GB.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_AR.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_CL.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_CO.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_CR.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_DO.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_EC.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_ES.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_MX.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_PE.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_PY.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/es_VE.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/et.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/eu.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/fa.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/fi.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/fr.po

Large diffs are not rendered by default.

540 changes: 540 additions & 0 deletions database_cleanup/i18n/fr_CA.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/fr_CH.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/gl.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/gl_ES.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/he.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/hr.po

Large diffs are not rendered by default.

540 changes: 540 additions & 0 deletions database_cleanup/i18n/hr_HR.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/hu.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/id.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/it.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/ja.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/ko.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/lt.po

Large diffs are not rendered by default.

540 changes: 540 additions & 0 deletions database_cleanup/i18n/lt_LT.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/lv.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/mk.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/mn.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/nb.po

Large diffs are not rendered by default.

540 changes: 540 additions & 0 deletions database_cleanup/i18n/nb_NO.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/nl.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/nl_BE.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/nl_NL.po

Large diffs are not rendered by default.

540 changes: 540 additions & 0 deletions database_cleanup/i18n/pl.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/pt.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/pt_BR.po

Large diffs are not rendered by default.

541 changes: 541 additions & 0 deletions database_cleanup/i18n/pt_PT.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/ro.po

Large diffs are not rendered by default.

540 changes: 540 additions & 0 deletions database_cleanup/i18n/ru.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/sk.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/sl.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/sr.po

Large diffs are not rendered by default.

540 changes: 540 additions & 0 deletions database_cleanup/i18n/sr@latin.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/sv.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/th.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/tr.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/tr_TR.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/uk.po

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions database_cleanup/i18n/vi.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/vi_VN.po

Large diffs are not rendered by default.

541 changes: 541 additions & 0 deletions database_cleanup/i18n/zh_CN.po

Large diffs are not rendered by default.

539 changes: 539 additions & 0 deletions database_cleanup/i18n/zh_TW.po

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions database_cleanup/identifier_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from psycopg2.extensions import ISQLQuote


class IdentifierAdapter(ISQLQuote):
def __init__(self, identifier, quote=True):
self.quote = quote
self.identifier = identifier

def __conform__(self, protocol):
if protocol == ISQLQuote:
return self

def getquoted(self):
def is_identifier_char(c):
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)
)
9 changes: 9 additions & 0 deletions database_cleanup/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from . import purge_wizard
from . import purge_modules
from . import purge_models
from . import purge_columns
from . import purge_tables
from . import purge_data
from . import purge_menus
from . import create_indexes
from . import purge_properties
82 changes: 82 additions & 0 deletions database_cleanup/models/create_indexes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright 2017 Therp BV <http://therp.nl>
# 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


class CreateIndexesLine(models.TransientModel):
_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)

@api.multi
def purge(self):
tables = set()
for field in self.mapped('field_id'):
model = self.env[field.model]
name = '%s_%s_index' % (model._table, field.name)
self.env.cr.execute(
'create index %s ON %s (%s)',
(
IdentifierAdapter(name, quote=False),
IdentifierAdapter(model._table),
IdentifierAdapter(field.name),
),
)
tables.add(model._table)
for table in tables:
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'

purge_line_ids = fields.One2many(
'cleanup.create_indexes.line', 'wizard_id',
)

@api.multi
def find(self):
res = list()
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)
self.env.cr.execute(
'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,)
)
if not self.env.cr.rowcount:
continue

res.append((0, 0, {
'name': '%s.%s' % (field.model, field.name),
'field_id': field.id,
}))
return res
132 changes: 132 additions & 0 deletions database_cleanup/models/purge_columns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Copyright 2014-2016 Therp BV <http://therp.nl>
# 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.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'

model_id = fields.Many2one('ir.model', 'Model', required=True,
ondelete='CASCADE')
wizard_id = fields.Many2one(
'cleanup.purge.wizard.column', 'Purge Wizard', readonly=True)

@api.multi
def purge(self):
"""
Unlink columns upon manual confirmation.
"""
if self:
objs = self
else:
objs = self.env['cleanup.purge.line.column']\
.browse(self._context.get('active_ids'))
for line in objs:
if line.purged:
continue
model_pool = self.env[line.model_id.model]
# Check whether the column actually still exists.
# 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))
if not self.env.cr.fetchone()[0]:
continue

self.logger.info(
'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})
# we need this commit because the ORM will deadlock if
# we still have a pending transaction
self.env.cr.commit() # pylint: disable=invalid-commit
return True


class CleanupPurgeWizardColumn(models.TransientModel):
_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'],
}

@api.model
def get_orphaned_columns(self, model_pools):
"""
From openobject-server/openerp/osv/orm.py
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 += models.MAGIC_COLUMNS
columns += self.blacklist.get(model_pools[0]._table, [])

self.env.cr.execute(
"SELECT a.attname FROM pg_class c, pg_attribute a "
"WHERE c.relname=%s AND c.oid=a.attrelid AND a.attisdropped=False "
"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)))
return [column for column, in self.env.cr.fetchall()]

@api.model
def find(self):
"""
Search for columns that are not in the corresponding model.

Group models by table to prevent false positives for columns
that are only in some of the models sharing the same table.
Example of this is 'sale_id' not being a field of stock.picking.in
"""
res = []

# mapping of tables to tuples (model id, [pool1, pool2, ...])
table2model = {}

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)

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]}))
if not res:
raise UserError(_('No orphaned columns found'))
return res

purge_line_ids = fields.One2many(
'cleanup.purge.line.column', 'wizard_id', 'Columns to purge')
Loading