From a88c520d03ae86bd7a8f9d08464beee4242bb227 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Fri, 31 Jul 2015 00:10:51 +0200 Subject: [PATCH 1/4] [IMP] db and common service cleanup - move check_super into db - remove some hardcoding from dispacth - hardcode wsgi handler and rpc endpoints --- openerp/addons/base/module/module.py | 7 --- openerp/http.py | 7 +-- openerp/service/common.py | 16 +++--- openerp/service/db.py | 79 +++++++++++++++++----------- openerp/service/security.py | 6 --- openerp/service/server.py | 2 +- openerp/service/wsgi_server.py | 22 +------- 7 files changed, 60 insertions(+), 79 deletions(-) diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index ec991a8c9ea..f0e6214f622 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -677,13 +677,6 @@ class module(osv.osv): self._update_dependencies(cr, uid, mod, terp.get('depends', [])) self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized')) - # Trigger load_addons if new module have been discovered it exists on - # wsgi handlers, so they can react accordingly - if tuple(res) != (0, 0): - for handler in openerp.service.wsgi_server.module_handlers: - if hasattr(handler, 'load_addons'): - handler.load_addons() - return res def download(self, cr, uid, ids, download=True, context=None): diff --git a/openerp/http.py b/openerp/http.py index 181d6ff4e8d..128a9526568 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -112,8 +112,6 @@ def dispatch_rpc(service_name, method, params): dispatch = openerp.service.model.dispatch elif service_name == 'report': dispatch = openerp.service.report.dispatch - else: - dispatch = openerp.service.wsgi_server.rpc_handlers.get(service_name) result = dispatch(method, params) if rpc_request_flag or rpc_response_flag: @@ -1471,7 +1469,7 @@ class Root(object): return request.registry['ir.http'].routing_map() def db_list(force=False, httprequest=None): - dbs = dispatch_rpc("db", "list", [force]) + dbs = openerp.service.db.list_dbs(force) return db_filter(dbs, httprequest=httprequest) def db_filter(dbs, httprequest=None): @@ -1621,6 +1619,5 @@ class CommonController(Controller): nsession = root.session_store.new() return nsession.sid -# register main wsgi handler +# main wsgi handler root = Root() -openerp.service.wsgi_server.register_wsgi_handler(root) diff --git a/openerp/service/common.py b/openerp/service/common.py index 212cb292c6e..8d7b5a505c5 100644 --- a/openerp/service/common.py +++ b/openerp/service/common.py @@ -17,14 +17,6 @@ RPC_VERSION_1 = { 'protocol_version': 1, } -def dispatch(method, params): - if method not in ['login', 'about', 'timezone_get', - 'version', 'authenticate', 'set_loglevel']: - raise Exception("Method not found: %s" % method) - - fn = globals()['exp_' + method] - return fn(*params) - def exp_login(db, login, password): # TODO: legacy indirection through 'security', should use directly # the res.users model @@ -57,3 +49,11 @@ def exp_set_loglevel(loglevel, logger=None): # TODO Previously, the level was set on the now deprecated # `openerp.netsvc.Logger` class. return True + +def dispatch(method, params): + g = globals() + exp_method_name = 'exp_' + method + if exp_method_name in g: + return g[exp_method_name](*params) + else: + raise Exception("Method not found: %s" % method) diff --git a/openerp/service/db.py b/openerp/service/db.py index 15726f2353f..bfb04eb8e0b 100644 --- a/openerp/service/db.py +++ b/openerp/service/db.py @@ -21,13 +21,21 @@ import openerp.release import openerp.sql_db import openerp.tools -import security - _logger = logging.getLogger(__name__) class DatabaseExists(Warning): pass +#---------------------------------------------------------- +# Master password required +#---------------------------------------------------------- + +def check_super(passwd): + if passwd == openerp.tools.config['admin_passwd']: + return True + else: + raise openerp.exceptions.AccessDenied() + # This should be moved to openerp.modules.db, along side initialize(). def _initialize_db(id, db_name, demo, lang, user_password): try: @@ -56,22 +64,6 @@ def _initialize_db(id, db_name, demo, lang, user_password): except Exception, e: _logger.exception('CREATE DATABASE failed:') -def dispatch(method, params): - if method in ['create', 'get_progress', 'drop', 'dump', 'restore', 'rename', - 'change_admin_password', 'migrate_databases', - 'create_database', 'duplicate_database']: - passwd = params[0] - params = params[1:] - security.check_super(passwd) - elif method in ['db_exist', 'list', 'list_lang', 'server_version']: - # params = params - # No security check for these methods - pass - else: - raise KeyError("Method not found: %s" % method) - fn = globals()['exp_' + method] - return fn(*params) - def _create_empty_database(name): db = openerp.sql_db.db_connect('postgres') with closing(db.cursor()) as cr: @@ -122,9 +114,8 @@ def _drop_conn(cr, db_name): except Exception: pass - def exp_drop(db_name): - if db_name not in exp_list(True): + if db_name not in list_dbs(True): return False openerp.modules.registry.RegistryManager.delete(db_name) openerp.sql_db.close_db(db_name) @@ -287,12 +278,28 @@ def exp_rename(old_name, new_name): shutil.move(old_fs, new_fs) return True +def exp_change_admin_password(new_password): + openerp.tools.config['admin_passwd'] = new_password + openerp.tools.config.save() + return True + +def exp_migrate_databases(databases): + for db in databases: + _logger.info('migrate database %s', db) + openerp.tools.config['update']['base'] = True + openerp.modules.registry.RegistryManager.new(db, force_demo=False, update_module=True) + return True + +#---------------------------------------------------------- +# No master password required +#---------------------------------------------------------- + @openerp.tools.mute_logger('openerp.sql_db') def exp_db_exist(db_name): ## Not True: in fact, check if connection to database is possible. The database may exists return bool(openerp.sql_db.db_connect(db_name)) -def exp_list(document=False): +def list_dbs(force=False): if not openerp.tools.config['list_db'] and not document: raise openerp.exceptions.AccessDenied() chosen_template = openerp.tools.config['db_template'] @@ -318,10 +325,10 @@ def exp_list(document=False): res.sort() return res -def exp_change_admin_password(new_password): - openerp.tools.config['admin_passwd'] = new_password - openerp.tools.config.save() - return True +def exp_list(document=False): + if not openerp.tools.config['list_db']: + raise openerp.exceptions.AccessDenied() + return list_dbs() def exp_list_lang(): return openerp.tools.scan_languages() @@ -332,9 +339,19 @@ def exp_server_version(): """ return openerp.release.version -def exp_migrate_databases(databases): - for db in databases: - _logger.info('migrate database %s', db) - openerp.tools.config['update']['base'] = True - openerp.modules.registry.RegistryManager.new(db, force_demo=False, update_module=True) - return True +#---------------------------------------------------------- +# db service dispatch +#---------------------------------------------------------- + +def dispatch(method, params): + g = globals() + exp_method_name = 'exp_' + method + if method in ['db_exist', 'list', 'list_lang', 'server_version']: + return g[exp_method_name](*params) + elif exp_method_name in g: + passwd = params[0] + params = params[1:] + check_super(passwd) + return g[exp_method_name](*params) + else: + raise KeyError("Method not found: %s" % method) diff --git a/openerp/service/security.py b/openerp/service/security.py index 255a3ea1b31..8ab38d3d659 100644 --- a/openerp/service/security.py +++ b/openerp/service/security.py @@ -8,12 +8,6 @@ def login(db, login, password): res_users = openerp.registry(db)['res.users'] return res_users._login(db, login, password) -def check_super(passwd): - if passwd == openerp.tools.config['admin_passwd']: - return True - else: - raise openerp.exceptions.AccessDenied() - def check(db, uid, passwd): res_users = openerp.registry(db)['res.users'] return res_users.check(db, uid, passwd) diff --git a/openerp/service/server.py b/openerp/service/server.py index 521c5ff8613..608b8478295 100644 --- a/openerp/service/server.py +++ b/openerp/service/server.py @@ -769,7 +769,7 @@ class WorkerCron(Worker): if config['db_name']: db_names = config['db_name'].split(',') else: - db_names = openerp.service.db.exp_list(True) + db_names = openerp.service.db.list_dbs(True) return db_names def process_work(self): diff --git a/openerp/service/wsgi_server.py b/openerp/service/wsgi_server.py index ef50e750b8f..8bbcc18030e 100644 --- a/openerp/service/wsgi_server.py +++ b/openerp/service/wsgi_server.py @@ -152,24 +152,6 @@ def wsgi_xmlrpc(environ, start_response): params, method = xmlrpclib.loads(data) return xmlrpc_return(start_response, service, method, params, string_faultcode) -# WSGI handlers registered through the register_wsgi_handler() function below. -module_handlers = [] -# RPC endpoints registered through the register_rpc_endpoint() function below. -rpc_handlers = {} - -def register_wsgi_handler(handler): - """ Register a WSGI handler. - - Handlers are tried in the order they are added. We might provide a way to - register a handler for specific routes later. - """ - module_handlers.append(handler) - -def register_rpc_endpoint(endpoint, handler): - """ Register a handler for a given RPC enpoint. - """ - rpc_handlers[endpoint] = handler - def application_unproxied(environ, start_response): """ WSGI entry point.""" # cleanup db/uid trackers - they're set at HTTP dispatch in @@ -184,9 +166,7 @@ def application_unproxied(environ, start_response): with openerp.api.Environment.manage(): # Try all handlers until one returns some result (i.e. not None). - wsgi_handlers = [wsgi_xmlrpc] - wsgi_handlers += module_handlers - for handler in wsgi_handlers: + for handler in [wsgi_xmlrpc, openerp.http.root]: result = handler(environ, start_response) if result is None: continue From 4b330f3173eb0a3d82b743c73de6cf5c9ecd0178 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Fri, 31 Jul 2015 01:53:08 +0200 Subject: [PATCH 2/4] [FIX] http jump to database selector on broken databases --- openerp/http.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/openerp/http.py b/openerp/http.py index 128a9526568..6daf9f01a24 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -1444,13 +1444,19 @@ class Root(object): try: with openerp.tools.mute_logger('openerp.sql_db'): ir_http = request.registry['ir.http'] - except (AttributeError, psycopg2.OperationalError): + except (AttributeError, psycopg2.OperationalError, psycopg2.ProgrammingError): # psycopg2 error or attribute error while constructing - # the registry. That means the database probably does - # not exists anymore or the code doesnt match the db. + # the registry. That means either + # - the database probably does not exists anymore + # - the database is corrupted + # - the database version doesnt match the server version # Log the user out and fall back to nodb request.session.logout() - result = _dispatch_nodb() + # If requesting /web this will loop + if request.httprequest.path == '/web': + result = werkzeug.utils.redirect('/web/database/selector') + else: + result = _dispatch_nodb() else: result = ir_http._dispatch() openerp.modules.registry.RegistryManager.signal_caches_change(db) From 3cba55d7a7e1f01150f87f806546e10526b10219 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Fri, 31 Jul 2015 00:33:47 +0200 Subject: [PATCH 3/4] [IMP] web: web 1.0 database manager Implement the database manager with plain HTML forms and HTTP controllers. --- addons/web/controllers/main.py | 150 +++--- .../src/img/logo_inverse_white_206px.png | Bin 0 -> 8208 bytes .../static/src/js/widgets/database_manager.js | 215 --------- addons/web/static/src/xml/base.xml | 277 ----------- addons/web/views/database_manager.html | 435 ++++++++++++------ addons/web/views/database_selector.html | 65 --- addons/web/views/webclient_templates.xml | 1 - addons/web_tests_demo/static/test/demo.js | 21 - 8 files changed, 363 insertions(+), 801 deletions(-) create mode 100644 addons/web/static/src/img/logo_inverse_white_206px.png delete mode 100644 addons/web/static/src/js/widgets/database_manager.js delete mode 100644 addons/web/views/database_selector.html diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 894faec7e51..911f42575d0 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -37,7 +37,6 @@ from openerp.tools import topological_sort from openerp.tools.translate import _ from openerp.tools import ustr from openerp import http - from openerp.http import request, serialize_exception as _serialize_exception from openerp.exceptions import AccessError @@ -679,118 +678,93 @@ class Proxy(http.Controller): class Database(http.Controller): - @http.route('/web/database/selector', type='http', auth="none") - def selector(self, **kw): + def _render_template(self, **d): + d.setdefault('manage',True) + d['insecure'] = openerp.tools.config['admin_passwd'] == 'admin' + d['list_db'] = openerp.tools.config['list_db'] + d['langs'] = openerp.service.db.exp_list_lang() + # databases list + d['databases'] = [] try: - dbs = http.db_list() - if not dbs: - return http.local_redirect('/web/database/manager') - except openerp.exceptions.AccessDenied: - dbs = False - return env.get_template("database_selector.html").render({ - 'databases': dbs, - 'debug': request.debug, - 'error': kw.get('error') - }) - - @http.route('/web/database/manager', type='http', auth="none") - def manager(self, **kw): - # TODO: migrate the webclient's database manager to server side views - request.session.logout() - return env.get_template("database_manager.html").render({ - 'modules': simplejson.dumps(module_boot()), - }) - - @http.route('/web/database/get_list', type='json', auth="none") - def get_list(self): - # TODO change js to avoid calling this method if in monodb mode - try: - return http.db_list() + d['databases'] = http.db_list() except openerp.exceptions.AccessDenied: monodb = db_monodb() if monodb: - return [monodb] - raise + d['databases'] = [monodb] + return env.get_template("database_manager.html").render(d) - @http.route('/web/database/create', type='json', auth="none") - def create(self, fields): - params = dict(map(operator.itemgetter('name', 'value'), fields)) - db_created = request.session.proxy("db").create_database( - params['super_admin_pwd'], - params['db_name'], - bool(params.get('demo_data')), - params['db_lang'], - params['create_admin_pwd']) - if db_created: - request.session.authenticate(params['db_name'], 'admin', params['create_admin_pwd']) - return db_created + @http.route('/web/database/selector', type='http', auth="none") + def selector(self, **kw): + return self._render_template(manage=False) - @http.route('/web/database/duplicate', type='json', auth="none") - def duplicate(self, fields): - params = dict(map(operator.itemgetter('name', 'value'), fields)) - duplicate_attrs = ( - params['super_admin_pwd'], - params['db_original_name'], - params['db_name'], - ) - - return request.session.proxy("db").duplicate_database(*duplicate_attrs) - - @http.route('/web/database/drop', type='json', auth="none") - def drop(self, fields): - password, db = operator.itemgetter( - 'drop_pwd', 'drop_db')( - dict(map(operator.itemgetter('name', 'value'), fields))) + @http.route('/web/database/manager', type='http', auth="none") + def manager(self, **kw): + return self._render_template() + @http.route('/web/database/create', type='http', auth="none") + def create(self, master_pwd, name, lang, password, **post): try: - if request.session.proxy("db").drop(password, db): - return True - else: - return False - except openerp.exceptions.AccessDenied: - return {'error': 'AccessDenied', 'title': 'Drop Database'} - except Exception: - return {'error': _('Could not drop database !'), 'title': _('Drop Database')} + request.session.proxy("db").create_database(master_pwd, name, bool(post.get('demo')), lang, password) + request.session.authenticate(name, login, password) + return http.local_redirect('/web/') + except Exception, e: + error = "Database creation error: %s" % e + return self._render_template(error=error) + + @http.route('/web/database/duplicate', type='http', auth="none") + def duplicate(self, master_pwd, name, new_name): + try: + request.session.proxy("db").duplicate_database(master_pwd, name, new_name) + return http.local_redirect('/web/database/manager') + except Exception, e: + error = "Database duplication error: %s" % e + return self._render_template(error=error) + + @http.route('/web/database/drop', type='http', auth="none") + def drop(self, master_pwd, name): + try: + request.session.proxy("db").drop(master_pwd, name) + return http.local_redirect('/web/database/manager') + except Exception, e: + error = "Database deletion error: %s" % e + return self._render_template(error=error) @http.route('/web/database/backup', type='http', auth="none") - def backup(self, backup_db, backup_pwd, token, backup_format='zip'): + def backup(self, master_pwd, name, backup_format = 'zip'): try: - openerp.service.security.check_super(backup_pwd) + openerp.service.db.check_super(master_pwd) ts = datetime.datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S") - filename = "%s_%s.%s" % (backup_db, ts, backup_format) + filename = "%s_%s.%s" % (name, ts, backup_format) headers = [ ('Content-Type', 'application/octet-stream; charset=binary'), ('Content-Disposition', content_disposition(filename)), ] - dump_stream = openerp.service.db.dump_db(backup_db, None, backup_format) + dump_stream = openerp.service.db.dump_db(name, None, backup_format) response = werkzeug.wrappers.Response(dump_stream, headers=headers, direct_passthrough=True) - response.set_cookie('fileToken', token) return response except Exception, e: _logger.exception('Database.backup') - return simplejson.dumps([[],[{'error': openerp.tools.ustr(e), 'title': _('Backup Database')}]]) + error = "Database backup error: %s" % e + return self._render_template(error=error) @http.route('/web/database/restore', type='http', auth="none") - def restore(self, db_file, restore_pwd, new_db, mode): + def restore(self, master_pwd, backup_file, name, copy=False): try: - copy = mode == 'copy' - data = base64.b64encode(db_file.read()) - request.session.proxy("db").restore(restore_pwd, new_db, data, copy) - return '' - except openerp.exceptions.AccessDenied, e: - raise Exception("AccessDenied") + data = base64.b64encode(backup_file.read()) + request.session.proxy("db").restore(master_pwd, name, data, copy) + return http.local_redirect('/web/database/manager') + except Exception, e: + error = "Database restore error: %s" % e + return self._render_template(error=error) - @http.route('/web/database/change_password', type='json', auth="none") - def change_password(self, fields): - old_password, new_password = operator.itemgetter( - 'old_pwd', 'new_pwd')( - dict(map(operator.itemgetter('name', 'value'), fields))) + @http.route('/web/database/change_password', type='http', auth="none") + def change_password(self, master_pwd, master_pwd_new): try: - return request.session.proxy("db").change_admin_password(old_password, new_password) - except openerp.exceptions.AccessDenied: - return {'error': 'AccessDenied', 'title': _('Change Password')} - except Exception: - return {'error': _('Error, password not changed !'), 'title': _('Change Password')} + request.session.proxy("db").change_admin_password(master_pwd, master_pwd_new) + return http.local_redirect('/web/database/manager') + except Exception, e: + error = "Master password update error: %s" % e + return self._render_template(error=error) class Session(http.Controller): diff --git a/addons/web/static/src/img/logo_inverse_white_206px.png b/addons/web/static/src/img/logo_inverse_white_206px.png new file mode 100644 index 0000000000000000000000000000000000000000..528d485f2fac9463af332c5a453033bd37871a6d GIT binary patch literal 8208 zcmb7JXH-*NvyOuFB1#7VX;P#Kp`$cKy3$J^6se(yqC|+G^xi{45fD&XKnxJ7bbJlH zgx(Fkh%_nT@_zT{z4ym`e$1Y8o;_#g%-U=1J$qta7--Q_u~Pv609x(mnnnP?P3W~g zKtXmbO<^D6uLm~&rxyOk-p>9(_I^$PwO8H_PCVM4_AX9FPWG?f`2KKG1^~FfYHO;Q zyq@09y$YC-XO37{-@Y; zygan#-{;y7SzE{L@;e$Y{%Sh8!SlB_iTerZwReEWh&{!>BgMag0d9v~Ns?a6)+$wd=qAYGS_Sw?akE(aO~AV-4j#aF^<-#+WsCQLtOhv%@Ie6}$+)`t z_WsZfz(u%|8Nl^@0lkf9d#dPvJX#g*-`^_xwNRU0-;44wCI!5r{aFDRk|_eH4GjNj zqXzIm5ZNT}1chy%ERb9cT(yQW)2IMesidKRA^swYHfUcpiRyr)G&w;3PSHo)FV8(r zfNJJ{o~5D>VQ9ACe**=83~*C5sY~R54o<+kIZ1MWDuM*ikSwkN_>Xp-m22V}*EzVx zf9L7nDcAVFh<`tOjsI!!{~@lkbB+JS;{QRsyZ)VPFrU(E>~ln1`GcQaPPa+aU(9Lm zz|po(YQ?U&?9v+R{<(J*nm@rzG{$p&$FgsqUxCr^uTQ<1q|q(?aQb&`cL?F5C;1)J zKQ3#7mIoWA{bvFWJU)-K|U{UG- zaq`_8^M74@C~xB^b=+wELN@ic`3cr6I6kAzjJqR8DvXwvZA;J)OCfP1S4Bu}(9vQd z+~zKl4;Mk}vkQgnpO)Lnm4tPJDFZ)XV>{xu+FjqxIDIv(DT*5}sx7!WymJw%3tr`t z7~-_AvLUmD*Hea+vY@e`aQOhkq_)Q;V|o^J&|-R@`WUdDp{@U{GJ~N@Rq~wEVQwkL zIb1R-JMz)wFdLHO;>ZYoPy1$?AalO7+#$&okfb1no?)T+WyTodqax}}?wr%{oDI+U zGP?G@Q8e>1sQNGQ>~Hex(ys{we!7I`qvXAFMQfrup_8TmroAQse5qw=3-o}~>qK{z%PIGuF za8{oy|3h}8>;{bQuSoD-s}^+Q_hPSn)YO9Gc9?b=ZR8m;7~mecq#Bmw7NHlm)r9fY^HZcE6BAlJUXP z&3!(>U}pRQBoOgz`R!%G1qRmZ!}$p*^+pq#a4MR{AB9Z?>k>Cn=KA(kB3_8CH*@9G zZG()BMW3BR_Sj=dTMxq+%J1Y9V%#JpXG(X$Nqo*%Te->%$Ec_Z31|`De zmtVZz->(WM_y_)cAu}+Rsg+?XQc@#(1I^D zWHfWz8;O;Ns#2+49(ljqr$|e-ui9r}uV3n2dR#ORAoQ?YU70I{B!buh&2{@&?i^-m zmhhf>Xazx>rWBHK);{#F5+-k~ku!QXWFpP?u)L=`V%B^=9TV~?8v0<@{#(n{fL_DlwZd4kI>$>@6YcS5+~IQQSMKSb(ELUWt7*n z8G^5mVO^bVLlg1$)*<;hHqC!`J*YiBB>NPyWuM3swJ2%C(-$VY+fC$Z)UsEK0m5ky z7-LF0In@TL7JD4l#POTXx;&26)F)A?3trHw#x%g(l4=>NOg^ zTnbn^PZjZXW9yEpIXjKtX?Y0Tl$$V{+R3*jO4*)}!M(z#M#p;)PfS%vGONo>Csnur zY9d5GwD1Z0mdhiWg3i8zNgbA`e$#d)leQl}vU$G1{oqr3?uk@@ePRor+w!p!P5QmG zErU0u5?v0@`BFGleyPQ@w7VT>TUij=WNF{*>|gK2p`ej3B^HY%==_Xk6$+D!C+60%FnoS|$JG^MQz`Og^}aBip0b-gS`)zd+6M2KI@ayyhag4oOjui=DX`QtW-aS< z`D;LCdYWg4z-87P>_>QLCrD(_!s={K>h~>JVEdqmJDIg0|M$U>5%#N;hN{0Byid2W zC72SS=K0yLuLt&SdH#&gzsrVaK{siWte8w}g0i3UH67zeblPhgYA!RMckY8m=L&DY zE5BvMwuPogI!6xDLNmeOm683)IFI4wy^RUIK)dF}?oF#o7L1!d9T zht>8$R;yjqu9cW9ZN|hiF_v0KMav)>tjDysB96%xKA~6W&eOvXaI(0S+buBF#=lDh zt-YM!qG>)3hQ(X_`Fesk?##htr(#$pi`Eg3(Xn$wEXumi7=p3mR-+$ZLQKiedE6eF zM$tfbT`ZAvZ)0aGyo$=8_@1g2-Vq?EHMEtT`aU0J{eh2;w3G}1%_32s$4;nVl&|b* z?0+Q|(fHzL6 zF_J^{@v}H$@UY*OaFQS!JEdPfq^EcaWKLwIUNE)h8SDJe`>dx^%oF^}Z|$`y`9xms%B))Tdl=@9piOfyxi?xvUH}T+)2)H~jiP;B)NhR*n6DdKl{b z)w$hw3%RE*-LKHam&FrdVI}QsBjDCWi7w`hno$0FPp41KX+hI4iMBi;yO>xiYg*`ZsmPPFW!dXDg5@nk37_W77hS#COXia+o^-ulMdcT( zMkt|?a{1)*t+ zKp6RXjo}b-km;CNjH@SsdX`#Y*X92BKQ8bp=9u`Su6M`NULaBUcwf^yH$zR&E@0QML4R+wh#rVX3WXVgR$jE5n#u z>j!~z8NubY-_z4#9~qUY$VopMu-je`ZWW(K=8kTn4ezXB3-4zO)A_pquj3Jal%USR zFaE86z;tC!K4@fnJEtc*N~Eu!pS~xXOfdmX{?AJodsf?Y&cDW;dNTC~c*HZf3N~h) zb&K8aj#X}fQF{XWMd-BiFF)zg9FjSbX=63a1;*@iQi;pjzPU=6K~Y=YtfoI5YlWcg zBU(Qs$()VGQv>TLWO+7$b^Tkm`|dP!0rqhlF^$L_HT&b2EA-{OyiQF20g&My-`u7$ zv|#*}oT*TQu1`;~o0)i!bide;8!Ch2V+-61Fj~?gcv)KhuzDHYHc(Td;%{D>lQobh zQTz)lmw~MsnjUmOYx~gCf>ft*A(6OHvc}S`wj#mHmNc2YfhXp$J*InxXtm1gT@d>L zJ`-V9rs9vxgTMaP7D(e?PKsT)CC8|8u4AytRpV;l)}` z%Y5IPB;nyZgo#4$QB02)P=IRqk9=x@q|#SIn6OOM^u@U6F*hGNx1nbEk?31dtyzlU zm+sXNdkunAyyoB;@ylBI*3&X4PL@75iM!fcVhmOt8(Q{(tGA_x|71q1-E8axC(+M4 zUj#_w+_G=>fOY~ZOSz($r2};3aex_7uY#j#GF|OIOun9P!Xtl86rD)!e12oDQ|0I! ze)kVPvEybGHm^t1UyuA`_1h(XapAk0b?QUKjD?Qi{o4xJoM^Sht19i;<6vd~(W^ z-XnQgoZGsYu+Q33$$KEqnQKO&iLF^w+$a_$C7tM7`F+oxKX4^@Q$*ABkAt^;a0htM z;lARrM`mxNLL=FXvWSph72CS4$UpBQJi|N&#Jw`P1wn->qtl~94RrBtba2cby56jV zv(_)Gz$tK-_1+N^=Yt5b!Qarccok7x-r`SI4i5^MQ&HM3Ct{gZ5VC{wmUzN$fyesZ zi%I{Lp26j95IF4kHDgT3PVQNJ$0RU`08EJYlf*II2~t^@E4+#~W8dJ)!^BoTONx6$ z`H-DdU$lqaO1I{OLJ6MBlg*Eees3=xSg(_;TiR!nFWRG8F>GDb-9HVpK6jO%oZTkO zMrS&li_&T;TK;+lLuh#PGh-*|1Ls&KWBYn#pYcv5mNqGr_F5FQ;5s;IHESKQW1p31 z?Y+de!8$w3J9i0RAB|yB9J@`vK(P_mCkT}}rt=Pv-uv8-39C1MK32(KNctH;C!4>< zVdNlDW3+{Iy6>B1g{ECkBmmO{3!#NV8)lxjVP7zVPoMi5Q|OCM$GzOD8nQ9cVr6{}0Z|vL(O3Rbsd7z{#LGl+rP@AImNnxYY0hh6@0{h-=NGQa8xhawn4lA_ za{89F(U2KWOJql&Z0xJzCWZXOUgQjS7s|z2@ALMZBDDUj`0B_+wMBl9z#??%sbx}3 z5piEI!l^t$TH%&I{WWyKzZ(|O8)U!ytPw@1Qpf%qRMzt=)|wY{qN^zt$BisR1z?h3 zC4+-Rt2yb z=J4#_T9zgX8-87^0|3<=gkT!@R<#x_0B~LBMh+iW$n6S6a0;{D>}x(Iv8TJkODF-w zTAz2lJ^4a-7A8qvfOVjtfHGqJ?Xoj!KE4F7#~d#{Ykm9jXx4;Q<8xsosFktpWZS$ZwPkXQM$<(JSk%s{#EZjEkNd21_x*fN1=NOq( z&yl)FEU1(0mbgJm+|&=F*^#lC8YHq%04 z1ufl^ex%B2g-h4!2%*gUYk+J>(`(xQpQo7;C4l;LiFMta0mWdK< zVmR*_S+Oej6l23=?&j?`{NwUD4(YB*R(SqigYbvETq_Ct(WwuSc)F)_HJI<)s`l0{ z%CfFvs`ik@y+Rd^>A1hsW!VgKOX&WC+ka0ajw2MhGU+0^a)lL2`nql1#Zt5%MeLY} ziSa>_RI{{3%Zlf(r=CM_0u#RqBw4IISUnV3cBORbYfw?-uSO_BVy;wYjWHi;O2Vua zoB43}x`9Mw=pU;E>H7G$$$b8)A1w9Q&y+m0++j#1bcsk!Tz6J&0iTLqK~ z<6f?gu(mk{9IE?jK*DIpmz<3!TVD{Bsq#kV7EyU zMe*vcfTO}Qg9l3;d*qG*2G)0dbxB~4_-@g5sa^V~GiPZneHovinpK!9BWtmtP7+Zl z))>DNDk1euEP*tkyni3I>+9;q>uQ(O>nV&i_u(Wr=aucu$^5dIS6$j=6{b|Gsw}E- zoKkK6$D-10{YC!jf%$EBDl(a>D7NTCwk2%N)vUbv-UL-^Cy?k~Wx#p(Pol&70JjEB zUD%r!MvDXE{p!mL<06kg#;1&`RnCbhWcu>A6t>7SI>5~gP`i(ZzH^PQf<@&MkE9xB zmyInTX`RSZL1*8S6Vh@2O?&=V)Uv?wk2YnN|OnwCU-G38}JD!LZ73lSI zW9zlMOm zRXlF)+c*!G8~&Q{W4I^`xP;akZ%z#34dU~doMnC&tdm$AlYK`&_?-9Qo;R6-SS{~X zB<2zGJs4s$K~!3x%_m{JrEukq$uSi9y`Kt7f|y6jW$>N22GTGp{AM}4oqMS)Cl{OO zGWNoE^pl)R8Fnz$h1F@c)%stl2SY73aO6Ng2#G3~AfWU2@$hjHec;|Y z0ps|oPob5k0Y2~}w{XSHz2ucZV+jWRc4+`O6u`uc3D5<)Rd{TpBQl~}*OB+!rs*-` zP5*$Q-gdqJTm)phBYvt3VfRAN+X&=X-}9-UpTHqgX}=&UOr87En)vDt8JGU7b}KAf zh79XOz2^AIXB+Behq;AK1CA&RsVEC`9&(b*y}z1Ax(1hM7JVTwugi#6))fG$dytMF zM_E^=N63#7dGM|z!%`Nje$@WEA3}{@gFJERu45=spM^(5DA7gf2(>D)N>BE!xQ@M$ z2Y4 zcF_{HL0|rsm-NDbMt>BwF7CNlaWmy3INE_I(v{OnC+37o-Ug{p1jTPvn^wd%<0z*Fy%)$IhYMUtQqaE~Pm)L9ydZOxCV?i$Mm59aHx-Kq#iI&#UoMNcG26P(ll4lB8HI`@lux`c52m$p?<3sVQ-F9ix3V9a z>laj6m%}nIj+QxE3}~UthO^`~S{PqA=a)$)TRV;S1a`lxK0z;?EAN^gvs*is9sLuu z%{^WTiIx?XDW3Q(+#-g(DSLfF=Cz~GHZi?H9}%H~IxSa+t31HPOd{##d*b9K*D@o_ z$EZ-_zhi5f8-Gk%1ht7ys+`jWj#T&Pple55Pd_K6l#~uCK~G=3R?f18u4Izv)R(k} z+0(ka@;4GeM>Jb>aFu>=oM6w!tfY%CHXuLDgiNVP^4sBM>0!R@&6T?c3gC09*{;_l zHTppr^Ug#E+wCE6J+t2#@Xs~}z4tUS(o=qJj{i~Xpe>}9nj?1iS#Fc|YVg>|^9HF) zWM6>F!q7e9nKv;tvhH0j2f=9F>O`uN>A+FE*~>w#Xx`op3)SA*3RSgy2`Nai;4f>! zdhp}MdZCcpO4qI)t!Z&3%U?C3w9HsE>v;4woJI8Dd`c* zn+vz*3ffo~(X#Jnt9QU7&k!0uqzds&Ms$Abbe9b4i>%=-RJEfcgZHS6J4mrU)vIMF zr*Jj8Ifhk-u(oNQ^|_IIq*)=o)jF%^b``-Kk)i)hQutTLJ>Xsq{|kBWZt*eH)|5)D zm?x@cMDn9jpTPB9=;8U6FK>)I=Z~HH0;n#4#<6F`uNEE&AVso2DE>=-h)(z zTGsr_mmD9$cSz4v9N)k;rE(#ld2KHG*Hv8HYWUaz^{@MlDBiHodeW4BOi4s!CwQgi zc+HM+3ozY?3SbH0-hRzw{JH>pbgmt_FlPf&_K?mQ@Ow0@K?WO?BrP2$uNCS2TMmO6 z(zB5|ZCnD~=cw-yIBme|4H!k5FS9kll*JN$%IbwGC3jwTqHmD3zIhsC&mKemWL{zP z$nm?<2kCNHE=AjD$VP#r7-x7=tM$)0y9Wn#Nr}JEfv*iat212exotj2VhoedH_#;4 zx)9vd_(YKbeu7ZPvwKbBcV2QzF}f#6K&{Xf$`P zfJq(Wb_$d0ry4m9{Q`YqJYBh6Ls3e{GWQ0@l4imS8iXcQJ~q`_oI^5iU)M#)_yPg} zQ?zcu{P;If!29P1pSQj+30zNZ=Ol{)mq!SqxJ_0!9K>foV1rgxT$8cAXkb_!IKc;< zZv7yh8PHUyyCSn^R@=ef{LxK+w|k=#*8HnHnWdf8r;839<8}k3j~q2?r)g~V&^S8o zDp-=)g((!F;otP;pxd+kgXQOWJ z7kZx$^6EByjVB&c;K~nJMGc9@t$58yY){cX%j->gtZncgO&7)WbH%LD&T()vQ7|X; zBBL=Y6fyHK@V#aeWutM(9K>`zc%A0vmKWl4yP|Z+v2)|1e|f>-^~#}ywl`5eP~1XG zT27EYvoA_fb*cW+R5oGhB~&I*xk=K9ic#YwDxLuM6uKL;bP(m#=)(@t1jc3^ySqy_ zDwx^EWbnpSwJ~^hMP0s0Q$dJ*kJrYL*1KBnZ5@q-?QbR6PaOEMj@i0!^D{$m%#>M) zRmfz1I^9!!?;2FhugC%BoV-u^byZ5VOI{nONXi5eBD;KZzuzH#taG-m(44Y*Kfi95 z-8z^gcburObe07=nmD;?qiyMju%pIh$p0FRH(WQe#gIE=C_=@A{KqzB)D*93%giCZ zY~E=Hjg7!+bfdk#Hxb`rihkyBoAMULUF}7CXRYgA|S|=W)xwHLLbh1I;RRyYT-4 DU+(~F literal 0 HcmV?d00001 diff --git a/addons/web/static/src/js/widgets/database_manager.js b/addons/web/static/src/js/widgets/database_manager.js deleted file mode 100644 index cbffa5117dc..00000000000 --- a/addons/web/static/src/js/widgets/database_manager.js +++ /dev/null @@ -1,215 +0,0 @@ -odoo.define('web.DatabaseManager', function (require) { -"use strict"; - -var core = require('web.core'); -var Dialog = require('web.Dialog'); -var framework = require('web.framework'); -var Widget = require('web.Widget'); - -var _t = core._t; -var QWeb = core.qweb; - -var DataBaseManager = Widget.extend({ - init: function(parent) { - this._super(parent); - $.validator.addMethod('matches', function (s, _, re) { - return new RegExp(re).test(s); - }, _t("Invalid database name")); - }, - start: function() { - var self = this; - $('.oe_secondary_menus_container,.oe_user_menu_placeholder').empty(); - var fetch_db = this.rpc("/web/database/get_list", {}).then( - function(result) { - self.db_list = result; - }, - function (_, ev) { - ev.preventDefault(); - self.db_list = null; - }); - var fetch_langs = this.rpc("/web/session/get_lang_list", {}).done(function(result) { - self.lang_list = result; - }); - return $.when(fetch_db, fetch_langs).always(self.do_render); - }, - do_render: function() { - var self = this; - core.bus.trigger('web_client_toggle_bars', true); - self.$el.html(QWeb.render("DatabaseManager", { widget : self })); - $('.oe_user_menu_placeholder').append(QWeb.render("DatabaseManager.user_menu",{ widget : self })); - $('.oe_secondary_menus_container').append(QWeb.render("DatabaseManager.menu",{ widget : self })); - $('ul.oe_secondary_submenu > li:first').addClass('active'); - $('ul.oe_secondary_submenu > li').bind('click', function (event) { - var menuitem = $(this); - menuitem.addClass('active').siblings().removeClass('active'); - var form_id =menuitem.find('a').attr('href'); - $(form_id).show().siblings().hide(); - event.preventDefault(); - }); - $('#back-to-login').click(self.do_exit); - self.$el.find("td").addClass("oe_form_group_cell"); - self.$el.find("tr td:first-child").addClass("oe_form_group_cell_label"); - self.$el.find("label").addClass("oe_form_label"); - self.$el.find("form[name=create_db_form]").validate({ submitHandler: self.do_create }); - self.$el.find("form[name=duplicate_db_form]").validate({ submitHandler: self.do_duplicate }); - self.$el.find("form[name=drop_db_form]").validate({ submitHandler: self.do_drop }); - self.$el.find("form[name=backup_db_form]").validate({ submitHandler: self.do_backup }); - self.$el.find("form[name=restore_db_form]").validate({ submitHandler: self.do_restore }); - self.$el.find("form[name=change_pwd_form]").validate({ - messages: { - old_pwd: _t("Please enter your previous password"), - new_pwd: _t("Please enter your new password"), - confirm_pwd: { - required: _t("Please confirm your new password"), - equalTo: _t("The confirmation does not match the password") - } - }, - submitHandler: self.do_change_password - }); - }, - destroy: function () { - this.$el.find('#db-create, #db-drop, #db-backup, #db-restore, #db-change-password, #back-to-login').unbind('click').end().empty(); - this._super(); - }, - /** - * Blocks UI and replaces $.unblockUI by a noop to prevent third parties - * from unblocking the UI - */ - blockUI: function () { - framework.blockUI(); - $.unblockUI = function () {}; - }, - /** - * Reinstates $.unblockUI so third parties can play with blockUI, and - * unblocks the UI - */ - unblockUI: function () { - $.unblockUI = framework.unblockUI; - framework.unblockUI(); - }, - /** - * Displays an error dialog resulting from the various RPC communications - * failing over themselves - * - * @param {Object} error error description - * @param {String} error.title title of the error dialog - * @param {String} error.error message of the error dialog - */ - display_error: function (error) { - return new Dialog(this, { - size: 'medium', - title: error.title, - $content: $('
').html(error.error) - }).open(); - }, - do_create: function(form) { - var fields = $(form).serializeArray(); - this.rpc("/web/database/create", {'fields': fields}).done(function(result) { - if (result) { - framework.redirect('/web'); - } else { - alert("Failed to create database"); - } - }); - }, - do_duplicate: function(form) { - var self = this; - var fields = $(form).serializeArray(); - self.rpc("/web/database/duplicate", {'fields': fields}).then(function(result) { - if (result.error) { - self.display_error(result); - return; - } - self.do_notify(_t("Duplicating database"), _t("The database has been duplicated.")); - self.start(); - }); - }, - do_drop: function(form) { - var self = this; - var $form = $(form), - fields = $form.serializeArray(), - $db_list = $form.find('[name=drop_db]'), - db = $db_list.val(); - if (!db || !confirm(_.str.sprintf(_t("Do you really want to delete the database: %s ?"), db))) { - return; - } - self.rpc("/web/database/drop", {'fields': fields}).done(function(result) { - if (result.error) { - self.display_error(result); - return; - } - self.do_notify(_t("Dropping database"), _.str.sprintf(_t("The database %s has been dropped"), db)); - self.start(); - }); - }, - do_backup: function(form) { - var self = this; - self.blockUI(); - self.session.get_file({ - form: form, - success: function () { - self.do_notify(_t("Backed"), _t("Database backed up successfully")); - }, - error: function(error){ - if (error && error[1]) { - self.display_error(error[1][0]); - } - }, - complete: function() { - self.unblockUI(); - } - }); - }, - do_restore: function(form) { - var self = this; - self.blockUI(); - $(form).ajaxSubmit({ - url: '/web/database/restore', - type: 'POST', - resetForm: true, - success: function (body) { - // If empty body, everything went fine - if (!body) { return; } - - if (body.indexOf('403 Forbidden') !== -1) { - self.display_error({ - title: _t("Access Denied"), - error: _t("Incorrect super-administrator password") - }); - } else { - self.display_error({ - title: _t("Restore Database"), - error: _t("Could not restore the database") - }); - } - }, - complete: function() { - self.unblockUI(); - self.do_notify(_t("Restored"), _t("Database restored successfully")); - } - }); - }, - do_change_password: function(form) { - var self = this; - self.rpc("/web/database/change_password", { - 'fields': $(form).serializeArray() - }).done(function(result) { - if (result.error) { - self.display_error(result); - return; - } - self.unblockUI(); - self.do_notify(_t("Changed Password"), _t("Password has been changed successfully")); - }); - }, - do_exit: function () { - this.$el.remove(); - framework.redirect('/web'); - } -}); - -core.action_registry.add("database_manager", DataBaseManager); - -return DataBaseManager; - -}); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 4bd7970c152..42d2f0ae34e 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -54,283 +54,6 @@
- -
-
-
-
-
-
-

- Create a New Database -

-
-
-
-

- Fill in this form to create an Odoo database. You can - create databases for different companies or for different - goals (testing, production). Once the database is created, - you will be able to install your first application. -

-

- By default, the master password is 'admin'. This password - is required to create, delete, dump or restore databases. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- - - Check this box to evaluate Odoo. - -
- -
-
- - - - - -
-
-
- -
  • - Back to Login -
  • -
    - -
    Database Management
    - -
    - - -
    -
    - - - - - - - - - - - - - - - - -
    - - -
    -
    -
    -
    -