[IMP] core: new neutralize flag on database restore and database duplicate dialog
Before this PR: The only way to neutralize the database is running cli command neutralize After this PR: There is a new checkbox "neutralize database" in Duplicate database and Restore database dialog that neutralize the database after duplication/restore. I also moved the neutralization code to the external module so it can be called also outside the cli . closes odoo/odoo#122185 X-original-commit: 616740e9d09b3d0376be43ed1489e390f6f5823e Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
This commit is contained in:
@@ -88,14 +88,14 @@ class Database(http.Controller):
|
||||
return self._render_template(error=error)
|
||||
|
||||
@http.route('/web/database/duplicate', type='http', auth="none", methods=['POST'], csrf=False)
|
||||
def duplicate(self, master_pwd, name, new_name):
|
||||
def duplicate(self, master_pwd, name, new_name, neutralize_database=False):
|
||||
insecure = odoo.tools.config.verify_admin_password('admin')
|
||||
if insecure and master_pwd:
|
||||
dispatch_rpc('db', 'change_admin_password', ["admin", master_pwd])
|
||||
try:
|
||||
if not re.match(DBNAME_PATTERN, new_name):
|
||||
raise Exception(_('Invalid database name. Only alphanumerical characters, underscore, hyphen and dot are allowed.'))
|
||||
dispatch_rpc('db', 'duplicate_database', [master_pwd, name, new_name])
|
||||
dispatch_rpc('db', 'duplicate_database', [master_pwd, name, new_name, neutralize_database])
|
||||
if request.db == name:
|
||||
request.env.cr.close() # duplicating a database leads to an unusable cursor
|
||||
return request.redirect('/web/database/manager')
|
||||
@@ -141,7 +141,7 @@ class Database(http.Controller):
|
||||
return self._render_template(error=error)
|
||||
|
||||
@http.route('/web/database/restore', type='http', auth="none", methods=['POST'], csrf=False)
|
||||
def restore(self, master_pwd, backup_file, name, copy=False):
|
||||
def restore(self, master_pwd, backup_file, name, copy=False, neutralize_database=False):
|
||||
insecure = odoo.tools.config.verify_admin_password('admin')
|
||||
if insecure and master_pwd:
|
||||
dispatch_rpc('db', 'change_admin_password', ["admin", master_pwd])
|
||||
@@ -150,7 +150,7 @@ class Database(http.Controller):
|
||||
db.check_super(master_pwd)
|
||||
with tempfile.NamedTemporaryFile(delete=False) as data_file:
|
||||
backup_file.save(data_file)
|
||||
db.restore_db(name, data_file.name, str2bool(copy))
|
||||
db.restore_db(name, data_file.name, str2bool(copy), neutralize_database)
|
||||
return request.redirect('/web/database/manager')
|
||||
except Exception as e:
|
||||
error = "Database restore error: %s" % (str(e) or repr(e))
|
||||
|
||||
@@ -134,6 +134,12 @@
|
||||
<input id="dbname_restore" type="text" name="name" class="form-control" required="required" t-att-pattern="pattern" title="Only alphanumerical characters, underscore, hyphen and dot are allowed"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="dbname_duplicate" class="col-md-4 col-form-label" >Neutralize</label>
|
||||
<div class="col-md-8">
|
||||
<input id="neutralize_database_restore" type="checkbox" name="neutralize_database" class="form-check-input" />
|
||||
</div>
|
||||
</div>
|
||||
<label for="radio_copy_true">This database might have been moved or copied.</label>
|
||||
<p class="form-text">
|
||||
In order to avoid conflicts between databases, Odoo needs to know if this database was moved or copied.<br/>
|
||||
@@ -211,6 +217,12 @@
|
||||
<input id="new_name" type="text" name="new_name" class="form-control" required="required" t-att-pattern="pattern" title="Only alphanumerical characters, underscore, hyphen and dot are allowed"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="dbname_duplicate" class="col-md-4 col-form-label" >Neutralize</label>
|
||||
<div class="col-md-8">
|
||||
<input id="neutralize_database" type="checkbox" name="neutralize_database" class="form-check-input" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="submit" value="Continue" class="btn btn-primary float-end"/>
|
||||
|
||||
+10
-2
@@ -50,6 +50,10 @@ class Db(Command):
|
||||
'-f', '--force', action='store_const', default=False, const=True,
|
||||
help="delete `database` database before loading if it exists"
|
||||
)
|
||||
load.add_argument(
|
||||
'-n', '--neutralize', action='store_const', default=False, const=True,
|
||||
help="neutralize the database after restore"
|
||||
)
|
||||
load.add_argument(
|
||||
'database', nargs='?',
|
||||
help="database to create, defaults to dump file's name "
|
||||
@@ -76,6 +80,10 @@ class Db(Command):
|
||||
'-f', '--force', action='store_const', default=False, const=True,
|
||||
help="delete `target` database before copying if it exists"
|
||||
)
|
||||
duplicate.add_argument(
|
||||
'-n', '--neutralize', action='store_const', default=False, const=True,
|
||||
help="neutralize the target database after duplicate"
|
||||
)
|
||||
duplicate.add_argument("source")
|
||||
duplicate.add_argument("target", help="database to copy `source` to, must not exist unless `-f` is specified in which case it will be dropped first")
|
||||
|
||||
@@ -134,7 +142,7 @@ class Db(Command):
|
||||
exit("Not a zipped dump file, use `pg_restore` to restore raw dumps,"
|
||||
" and `psql` to execute sql dumps or scripts.")
|
||||
|
||||
restore_db(db=db_name, dump_file=dump_file, copy=True)
|
||||
restore_db(db=db_name, dump_file=dump_file, copy=True, neutralize_database=args.neutralize)
|
||||
|
||||
def dump(self, args):
|
||||
if args.dump_path == '-':
|
||||
@@ -145,7 +153,7 @@ class Db(Command):
|
||||
|
||||
def duplicate(self, args):
|
||||
self._check_target(args.target, delete_if_exists=args.force)
|
||||
exp_duplicate_database(args.source, args.target)
|
||||
exp_duplicate_database(args.source, args.target, neutralize_database=args.neutralize)
|
||||
|
||||
def rename(self, args):
|
||||
self._check_target(args.target, delete_if_exists=args.force)
|
||||
|
||||
@@ -33,9 +33,9 @@ class Neutralize(Command):
|
||||
|
||||
try:
|
||||
with odoo.sql_db.db_connect(dbname).cursor() as cursor:
|
||||
installed_modules = odoo.modules.neutralize.get_installed_modules(cursor)
|
||||
queries = odoo.modules.neutralize.get_neutralization_queries(installed_modules)
|
||||
if opt.to_stdout:
|
||||
installed_modules = odoo.modules.neutralize.get_installed_modules(cursor)
|
||||
queries = odoo.modules.neutralize.get_neutralization_queries(installed_modules)
|
||||
# pylint: disable=bad-builtin
|
||||
print('BEGIN;')
|
||||
for query in queries:
|
||||
@@ -44,9 +44,8 @@ class Neutralize(Command):
|
||||
# pylint: disable=bad-builtin
|
||||
print("COMMIT;")
|
||||
else:
|
||||
for query in queries:
|
||||
cursor.execute(query)
|
||||
_logger.info("Neutralization finished")
|
||||
odoo.modules.neutralize.neutralize_database(cursor)
|
||||
|
||||
except Exception:
|
||||
_logger.critical("An error occurred during the neutralization. THE DATABASE IS NOT NEUTRALIZED!")
|
||||
sys.exit(1)
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import odoo
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
def get_installed_modules(cursor):
|
||||
cursor.execute('''
|
||||
@@ -19,3 +21,10 @@ def get_neutralization_queries(modules):
|
||||
if filename:
|
||||
with odoo.tools.misc.file_open(filename) as file:
|
||||
yield file.read().strip()
|
||||
|
||||
def neutralize_database(cursor):
|
||||
installed_modules = get_installed_modules(cursor)
|
||||
queries = get_neutralization_queries(installed_modules)
|
||||
for query in queries:
|
||||
cursor.execute(query)
|
||||
_logger.info("Neutralization finished")
|
||||
|
||||
+7
-2
@@ -142,7 +142,7 @@ def exp_create_database(db_name, demo, lang, user_password='admin', login='admin
|
||||
return True
|
||||
|
||||
@check_db_management_enabled
|
||||
def exp_duplicate_database(db_original_name, db_name):
|
||||
def exp_duplicate_database(db_original_name, db_name, neutralize_database=False):
|
||||
_logger.info('Duplicate database `%s` to `%s`.', db_original_name, db_name)
|
||||
odoo.sql_db.close_db(db_original_name)
|
||||
db = odoo.sql_db.db_connect('postgres')
|
||||
@@ -160,6 +160,8 @@ def exp_duplicate_database(db_original_name, db_name):
|
||||
# if it's a copy of a database, force generation of a new dbuuid
|
||||
env = odoo.api.Environment(cr, SUPERUSER_ID, {})
|
||||
env['ir.config_parameter'].init(force=True)
|
||||
if neutralize_database:
|
||||
odoo.modules.neutralize.neutralize_database(cr)
|
||||
|
||||
from_fs = odoo.tools.config.filestore(db_original_name)
|
||||
to_fs = odoo.tools.config.filestore(db_name)
|
||||
@@ -284,7 +286,7 @@ def exp_restore(db_name, data, copy=False):
|
||||
return True
|
||||
|
||||
@check_db_management_enabled
|
||||
def restore_db(db, dump_file, copy=False):
|
||||
def restore_db(db, dump_file, copy=False, neutralize_database=False):
|
||||
assert isinstance(db, str)
|
||||
if exp_db_exist(db):
|
||||
_logger.warning('RESTORE DB: %s already exists', db)
|
||||
@@ -328,6 +330,9 @@ def restore_db(db, dump_file, copy=False):
|
||||
if copy:
|
||||
# if it's a copy of a database, force generation of a new dbuuid
|
||||
env['ir.config_parameter'].init(force=True)
|
||||
if neutralize_database:
|
||||
odoo.modules.neutralize.neutralize_database(cr)
|
||||
|
||||
if filestore_path:
|
||||
filestore_dest = env['ir.attachment']._filestore()
|
||||
shutil.move(filestore_path, filestore_dest)
|
||||
|
||||
Reference in New Issue
Block a user