-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
-# $Id$
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# GNU Affero General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-import base64
+import base64
import logging
import os
import security
-import string
import thread
import threading
import time
-
+import sys
+import platform
from tools.translate import _
import addons
import ir
import release
import sql_db
import tools
+import locale
+from cStringIO import StringIO
logging.basicConfig()
-class db(netsvc.Service):
+class db(netsvc.ExportService):
def __init__(self, name="db"):
- netsvc.Service.__init__(self, name)
+ netsvc.ExportService.__init__(self, name)
self.joinGroup("web-services")
- self.exportMethod(self.create)
- self.exportMethod(self.get_progress)
- self.exportMethod(self.drop)
- self.exportMethod(self.dump)
- self.exportMethod(self.restore)
- self.exportMethod(self.list)
- self.exportMethod(self.list_lang)
- self.exportMethod(self.change_admin_password)
- self.exportMethod(self.server_version)
- self.exportMethod(self.migrate_databases)
self.actions = {}
self.id = 0
self.id_protect = threading.Semaphore()
- def create(self, password, db_name, demo, lang, user_password='admin'):
- security.check_super(password)
+ self._pg_psw_env_var_is_set = False # on win32, pg_dump need the PGPASSWORD env var
+
+ def dispatch(self, method, auth, params):
+ if method in [ 'create', 'get_progress', 'drop', 'dump',
+ 'restore', 'rename',
+ 'change_admin_password', 'migrate_databases' ]:
+ 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 = getattr(self, 'exp_'+method)
+ return fn(*params)
+
+ def new_dispatch(self,method,auth,params):
+ pass
+ def _create_empty_database(self, name):
+ db = sql_db.db_connect('template1')
+ cr = db.cursor()
+ try:
+ cr.autocommit(True) # avoid transaction block
+ cr.execute("""CREATE DATABASE "%s" ENCODING 'unicode' TEMPLATE "template0" """ % name)
+ finally:
+ cr.close()
+
+ def exp_create(self, db_name, demo, lang, user_password='admin'):
self.id_protect.acquire()
self.id += 1
id = self.id
self.actions[id] = {'clean': False}
- db = sql_db.db_connect('template1', serialize=1)
- cr = db.cursor()
- cr.autocommit(True)
- time.sleep(0.2)
- cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'')
- cr.close()
+ self._create_empty_database(db_name)
+
class DBInitialize(object):
def __call__(self, serv, id, db_name, demo, lang, user_password='admin'):
+ cr = None
try:
serv.actions[id]['progress'] = 0
- clean = False
cr = sql_db.db_connect(db_name).cursor()
tools.init_db(cr)
cr.commit()
except Exception, e:
serv.actions[id]['clean'] = False
serv.actions[id]['exception'] = e
- from StringIO import StringIO
import traceback
e_str = StringIO()
traceback.print_exc(file=e_str)
self.actions[id]['thread'] = create_thread
return id
- def get_progress(self, password, id):
- security.check_super(password)
+ def exp_get_progress(self, id):
if self.actions[id]['thread'].isAlive():
# return addons.init_progress[db_name]
return (min(self.actions[id].get('progress', 0),0.95), [])
clean = self.actions[id]['clean']
if clean:
users = self.actions[id]['users']
- del self.actions[id]
+ self.actions.pop(id)
return (1.0, users)
else:
e = self.actions[id]['exception']
- del self.actions[id]
+ self.actions.pop(id)
raise Exception, e
- def drop(self, password, db_name):
- security.check_super(password)
+ def exp_drop(self, db_name):
sql_db.close_db(db_name)
logger = netsvc.Logger()
- db = sql_db.db_connect('template1', serialize=1)
+ db = sql_db.db_connect('template1')
cr = db.cursor()
- cr.autocommit(True)
+ cr.autocommit(True) # avoid transaction block
try:
try:
- cr.execute('DROP DATABASE ' + db_name)
+ cr.execute('DROP DATABASE "%s"' % db_name)
except Exception, e:
logger.notifyChannel("web-services", netsvc.LOG_ERROR,
'DROP DB: %s failed:\n%s' % (db_name, e))
cr.close()
return True
- def dump(self, password, db_name):
- security.check_super(password)
+ def _set_pg_psw_env_var(self):
+ if os.name == 'nt' and not os.environ.get('PGPASSWORD', ''):
+ os.environ['PGPASSWORD'] = tools.config['db_password']
+ self._pg_psw_env_var_is_set = True
+
+ def _unset_pg_psw_env_var(self):
+ if os.name == 'nt' and self._pg_psw_env_var_is_set:
+ os.environ['PGPASSWORD'] = ''
+
+ def exp_dump(self, db_name):
logger = netsvc.Logger()
- cmd = ['pg_dump', '--format=c']
+ self._set_pg_psw_env_var()
+
+ cmd = ['pg_dump', '--format=c', '--no-owner']
if tools.config['db_user']:
cmd.append('--username=' + tools.config['db_user'])
if tools.config['db_host']:
cmd.append('--host=' + tools.config['db_host'])
if tools.config['db_port']:
- cmd.append('--port=' + tools.config['db_port'])
+ cmd.append('--port=' + str(tools.config['db_port']))
cmd.append(db_name)
stdin, stdout = tools.exec_pg_command_pipe(*tuple(cmd))
raise Exception, "Couldn't dump database"
logger.notifyChannel("web-services", netsvc.LOG_INFO,
'DUMP DB: %s' % (db_name))
+
+ self._unset_pg_psw_env_var()
+
return base64.encodestring(data)
- def restore(self, password, db_name, data):
- security.check_super(password)
+ def exp_restore(self, db_name, data):
logger = netsvc.Logger()
+ self._set_pg_psw_env_var()
+
if self.db_exist(db_name):
logger.notifyChannel("web-services", netsvc.LOG_WARNING,
'RESTORE DB: %s already exists' % (db_name,))
raise Exception, "Database already exists"
- db = sql_db.db_connect('template1', serialize=1)
- cr = db.cursor()
- cr.autocommit(True)
- cr.execute('CREATE DATABASE ' + db_name + ' ENCODING \'unicode\'')
- cr.close()
+ self._create_empty_database(db_name)
- cmd = ['pg_restore']
+ cmd = ['pg_restore', '--no-owner']
if tools.config['db_user']:
cmd.append('--username=' + tools.config['db_user'])
if tools.config['db_host']:
cmd.append('--host=' + tools.config['db_host'])
if tools.config['db_port']:
- cmd.append('--port=' + tools.config['db_port'])
+ cmd.append('--port=' + str(tools.config['db_port']))
cmd.append('--dbname=' + db_name)
args2 = tuple(cmd)
raise Exception, "Couldn't restore database"
logger.notifyChannel("web-services", netsvc.LOG_INFO,
'RESTORE DB: %s' % (db_name))
+
+ self._unset_pg_psw_env_var()
+
return True
- def db_exist(self, db_name):
- try:
- db = sql_db.db_connect(db_name)
- return True
- except:
- return False
+ def exp_rename(self, old_name, new_name):
+ sql_db.close_db(old_name)
+ logger = netsvc.Logger()
- def list(self):
db = sql_db.db_connect('template1')
+ cr = db.cursor()
try:
- cr = db.cursor()
- db_user = tools.config["db_user"]
- if not db_user and os.name == 'posix':
- import pwd
- db_user = pwd.getpwuid(os.getuid())[0]
- if not db_user:
- cr.execute("select decode(usename, 'escape') from pg_user where usesysid=(select datdba from pg_database where datname=%s)", (tools.config["db_name"],))
- res = cr.fetchone()
- db_user = res and str(res[0])
- if db_user:
- cr.execute("select decode(datname, 'escape') from pg_database where datdba=(select usesysid from pg_user where usename=%s) and datname not in ('template0', 'template1', 'postgres')", (db_user,))
+ try:
+ cr.execute('ALTER DATABASE "%s" RENAME TO "%s"' % (old_name, new_name))
+ except Exception, e:
+ logger.notifyChannel("web-services", netsvc.LOG_ERROR,
+ 'RENAME DB: %s -> %s failed:\n%s' % (old_name, new_name, e))
+ raise Exception("Couldn't rename database %s to %s: %s" % (old_name, new_name, e))
else:
- cr.execute("select decode(datname, 'escape') from pg_database where datname not in('template0', 'template1','postgres')")
- res = [str(name) for (name,) in cr.fetchall()]
+ fs = os.path.join(tools.config['root_path'], 'filestore')
+ if os.path.exists(os.path.join(fs, old_name)):
+ os.rename(os.path.join(fs, old_name), os.path.join(fs, new_name))
+
+ logger.notifyChannel("web-services", netsvc.LOG_INFO,
+ 'RENAME DB: %s -> %s' % (old_name, new_name))
+ finally:
+ cr.close()
+ return True
+
+ def exp_db_exist(self, db_name):
+ ## Not True: in fact, check if connection to database is possible. The database may exists
+ return bool(sql_db.db_connect(db_name))
+
+ def exp_list(self):
+ if not tools.config['list_db']:
+ raise Exception('AccessDenied')
+
+ db = sql_db.db_connect('template1')
+ cr = db.cursor()
+ try:
+ try:
+ db_user = tools.config["db_user"]
+ if not db_user and os.name == 'posix':
+ import pwd
+ db_user = pwd.getpwuid(os.getuid())[0]
+ if not db_user:
+ cr.execute("select decode(usename, 'escape') from pg_user where usesysid=(select datdba from pg_database where datname=%s)", (tools.config["db_name"],))
+ res = cr.fetchone()
+ db_user = res and str(res[0])
+ if db_user:
+ cr.execute("select decode(datname, 'escape') from pg_database where datdba=(select usesysid from pg_user where usename=%s) and datname not in ('template0', 'template1', 'postgres') order by datname", (db_user,))
+ else:
+ cr.execute("select decode(datname, 'escape') from pg_database where datname not in('template0', 'template1','postgres') order by datname")
+ res = [str(name) for (name,) in cr.fetchall()]
+ except:
+ res = []
+ finally:
cr.close()
- except:
- res = []
res.sort()
return res
- def change_admin_password(self, old_password, new_password):
- security.check_super(old_password)
+ def exp_change_admin_password(self, new_password):
tools.config['admin_passwd'] = new_password
tools.config.save()
return True
- def list_lang(self):
+ def exp_list_lang(self):
return tools.scan_languages()
- def server_version(self):
+ def exp_server_version(self):
""" Return the version of the server
Used by the client to verify the compatibility with its own version
"""
return release.version
- def migrate_databases(self, password, databases):
- security.check_super(password)
+ def exp_migrate_databases(self,databases):
+
+ from osv.orm import except_orm
+ from osv.osv import except_osv
+
l = netsvc.Logger()
for db in databases:
try:
l.notifyChannel('migration', netsvc.LOG_INFO, 'migrate database %s' % (db,))
tools.config['update']['base'] = True
- pooler.restart_pool(db, force_demo=False, update_module=True)
- except Exception, e:
- tools.debug(e)
+ pooler.restart_pool(db, force_demo=False, update_module=True)
+ except except_orm, inst:
+ self.abortResponse(1, inst.name, 'warning', inst.value)
+ except except_osv, inst:
+ self.abortResponse(1, inst.name, inst.exc_type, inst.value)
+ except Exception:
+ import traceback
+ tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback))
+ l.notifyChannel('web-services', netsvc.LOG_ERROR, tb_s)
raise
+ return True
db()
-class MigrationException(Exception): pass
+class _ObjectService(netsvc.ExportService):
+ "A common base class for those who have fn(db, uid, password,...) "
-class common(netsvc.Service):
- def __init__(self,name="common"):
- netsvc.Service.__init__(self,name)
- self.joinGroup("web-services")
- self.exportMethod(self.ir_get)
- self.exportMethod(self.ir_set)
- self.exportMethod(self.ir_del)
- self.exportMethod(self.about)
- self.exportMethod(self.login)
- self.exportMethod(self.logout)
- self.exportMethod(self.timezone_get)
- self.exportMethod(self.get_migration_scripts)
-
- def ir_set(self, db, uid, password, keys, args, name, value, replace=True, isobject=False):
- security.check(db, uid, password)
+ def common_dispatch(self, method, auth, params):
+ (db, uid, passwd ) = params[0:3]
+ params = params[3:]
+ security.check(db,uid,passwd)
cr = pooler.get_db(db).cursor()
- res = ir.ir_set(cr,uid, keys, args, name, value, replace, isobject)
+ fn = getattr(self, 'exp_'+method)
+ res = fn(cr, uid, *params)
cr.commit()
cr.close()
return res
- def ir_del(self, db, uid, password, id):
- security.check(db, uid, password)
- cr = pooler.get_db(db).cursor()
+class common(_ObjectService):
+ def __init__(self,name="common"):
+ _ObjectService.__init__(self,name)
+ self.joinGroup("web-services")
+
+ def dispatch(self, method, auth, params):
+ logger = netsvc.Logger()
+ if method in [ 'ir_set','ir_del', 'ir_get' ]:
+ return self.common_dispatch(method,auth,params)
+ if method == 'login':
+ # At this old dispatcher, we do NOT update the auth proxy
+ res = security.login(params[0], params[1], params[2])
+ msg = res and 'successful login' or 'bad login or password'
+ # TODO log the client ip address..
+ logger.notifyChannel("web-service", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, params[1], params[0].lower()))
+ return res or False
+ elif method == 'logout':
+ if auth:
+ auth.logout(params[1])
+ logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout %s from database %s'%(login,db))
+ return True
+ elif method in ['about', 'timezone_get', 'get_server_environment',
+ 'login_message','get_stats', 'check_connectivity']:
+ pass
+ elif method in ['get_available_updates', 'get_migration_scripts', 'set_loglevel']:
+ passwd = params[0]
+ params = params[1:]
+ security.check_super(passwd)
+ else:
+ raise Exception("Method not found: %s" % method)
+
+ fn = getattr(self, 'exp_'+method)
+ return fn(*params)
+
+
+ def new_dispatch(self,method,auth,params):
+ pass
+
+ def exp_ir_set(self, cr, uid, keys, args, name, value, replace=True, isobject=False):
+ res = ir.ir_set(cr,uid, keys, args, name, value, replace, isobject)
+ return res
+
+ def exp_ir_del(self, cr, uid, id):
res = ir.ir_del(cr,uid, id)
- cr.commit()
- cr.close()
return res
- def ir_get(self, db, uid, password, keys, args=None, meta=None, context=None):
+ def exp_ir_get(self, cr, uid, keys, args=None, meta=None, context=None):
if not args:
args=[]
if not context:
context={}
- security.check(db, uid, password)
- cr = pooler.get_db(db).cursor()
res = ir.ir_get(cr,uid, keys, args, meta, context)
- cr.commit()
- cr.close()
return res
- def login(self, db, login, password):
- res = security.login(db, login, password)
- logger = netsvc.Logger()
- msg = res and 'successful login' or 'bad login or password'
- logger.notifyChannel("web-service", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, login, db.lower()))
- return res or False
-
- def logout(self, db, login, password):
- logger = netsvc.Logger()
- logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout %s from database %s'%(login,db))
- return True
-
- def about(self, extended=False):
+ def exp_about(self, extended=False):
"""Return information about the OpenERP Server.
@param extended: if True then return version info
return info, release.version
return info
- def timezone_get(self, db, login, password):
- return time.tzname[0]
+ def exp_timezone_get(self, db, login, password):
+ #timezone detection is safe in multithread, so lazy init is ok here
+ if (not tools.config['timezone']):
+ tools.config['timezone'] = tools.misc.detect_server_timezone()
+ return tools.config['timezone']
+
+
+ def exp_get_available_updates(self, contract_id, contract_password):
+ import tools.maintenance as tm
+ try:
+ rc = tm.remote_contract(contract_id, contract_password)
+ if not rc.id:
+ raise tm.RemoteContractException('This contract does not exist or is not active')
+
+ return rc.get_available_updates(rc.id, addons.get_modules_with_version())
+
+ except tm.RemoteContractException, e:
+ self.abortResponse(1, 'Migration Error', 'warning', str(e))
- def get_migration_scripts(self, password, contract_id, contract_password):
- security.check_super(password)
+ def exp_get_migration_scripts(self, contract_id, contract_password):
l = netsvc.Logger()
- try:
- from tools.maintenance import remote_contract
- rc = remote_contract(contract_id, contract_password)
+ import tools.maintenance as tm
+ try:
+ rc = tm.remote_contract(contract_id, contract_password)
if not rc.id:
- raise MigrationException('This contract does not exist or is not active')
+ raise tm.RemoteContractException('This contract does not exist or is not active')
if rc.status != 'full':
- raise MigrationException('Can not get updates for a partial contract')
+ raise tm.RemoteContractException('Can not get updates for a partial contract')
l.notifyChannel('migration', netsvc.LOG_INFO, 'starting migration with contract %s' % (rc.name,))
- zips = rc.retrieve_updates(rc.id)
-
- from shutil import rmtree
+ zips = rc.retrieve_updates(rc.id, addons.get_modules_with_version())
+
+ from shutil import rmtree, copytree, copy
+
+ backup_directory = os.path.join(tools.config['root_path'], 'backup', time.strftime('%Y-%m-%d-%H-%M'))
+ if zips and not os.path.isdir(backup_directory):
+ l.notifyChannel('migration', netsvc.LOG_INFO, 'create a new backup directory to \
+ store the old modules: %s' % (backup_directory,))
+ os.makedirs(backup_directory)
+
for module in zips:
l.notifyChannel('migration', netsvc.LOG_INFO, 'upgrade module %s' % (module,))
mp = addons.get_module_path(module)
if mp:
if os.path.isdir(mp):
- rmtree(os.path.realpath(mp))
+ copytree(mp, os.path.join(backup_directory, module))
+ if os.path.islink(mp):
+ os.unlink(mp)
+ else:
+ rmtree(mp)
else:
+ copy(mp + 'zip', backup_directory)
os.unlink(mp + '.zip')
- mp = os.path.join(tools.config['addons_path'], module + '.zip')
+ try:
+ try:
+ base64_decoded = base64.decodestring(zips[module])
+ except:
+ l.notifyChannel('migration', netsvc.LOG_ERROR, 'unable to read the module %s' % (module,))
+ raise
+
+ zip_contents = StringIO(base64_decoded)
+ zip_contents.seek(0)
+ try:
+ try:
+ tools.extract_zip_file(zip_contents, tools.config['addons_path'] )
+ except:
+ l.notifyChannel('migration', netsvc.LOG_ERROR, 'unable to extract the module %s' % (module, ))
+ rmtree(module)
+ raise
+ finally:
+ zip_contents.close()
+ except:
+ l.notifyChannel('migration', netsvc.LOG_ERROR, 'restore the previous version of the module %s' % (module, ))
+ nmp = os.path.join(backup_directory, module)
+ if os.path.isdir(nmp):
+ copytree(nmp, tools.config['addons_path'])
+ else:
+ copy(nmp+'.zip', tools.config['addons_path'])
+ raise
- zip = open(mp, 'w')
- zip.write(base64.decodestring(zips[module]))
- zip.close()
- except MigrationException, e:
+ return True
+ except tm.RemoteContractException, e:
self.abortResponse(1, 'Migration Error', 'warning', str(e))
except Exception, e:
import traceback
tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback))
l.notifyChannel('migration', netsvc.LOG_ERROR, tb_s)
raise
-
+
+ def exp_get_server_environment(self):
+ os_lang = '.'.join( [x for x in locale.getdefaultlocale() if x] )
+ if not os_lang:
+ os_lang = 'NOT SET'
+ environment = '\nEnvironment Information : \n' \
+ 'System : %s\n' \
+ 'OS Name : %s\n' \
+ %(platform.platform(), platform.os.name)
+ if os.name == 'posix':
+ if platform.system() == 'Linux':
+ lsbinfo = os.popen('lsb_release -a').read()
+ environment += '%s'%(lsbinfo)
+ else:
+ environment += 'Your System is not lsb compliant\n'
+ environment += 'Operating System Release : %s\n' \
+ 'Operating System Version : %s\n' \
+ 'Operating System Architecture : %s\n' \
+ 'Operating System Locale : %s\n'\
+ 'Python Version : %s\n'\
+ 'OpenERP-Server Version : %s'\
+ %(platform.release(), platform.version(), platform.architecture()[0],
+ os_lang, platform.python_version(),release.version)
+ return environment
+
+ def exp_login_message(self):
+ return tools.config.get('login_message', False)
+
+ def exp_set_loglevel(self,loglevel):
+ l = netsvc.Logger()
+ l.set_loglevel(int(loglevel))
+ return True
+
+ def exp_get_stats(self):
+ import threading
+ res = "OpenERP server: %d threads\n" % threading.active_count()
+ res += netsvc.Server.allStats()
+ return res
+
+ def exp_check_connectivity(self):
+ return bool(sql_db.db_connect('template1'))
+
common()
-class objects_proxy(netsvc.Service):
+class objects_proxy(netsvc.ExportService):
def __init__(self, name="object"):
- netsvc.Service.__init__(self,name)
+ netsvc.ExportService.__init__(self,name)
self.joinGroup('web-services')
- self.exportMethod(self.execute)
- self.exportMethod(self.exec_workflow)
- self.exportMethod(self.obj_list)
-
- def exec_workflow(self, db, uid, passwd, object, method, id):
- security.check(db, uid, passwd)
- service = netsvc.LocalService("object_proxy")
- res = service.exec_workflow(db, uid, object, method, id)
- return res
- def execute(self, db, uid, passwd, object, method, *args):
- security.check(db, uid, passwd)
- service = netsvc.LocalService("object_proxy")
- res = service.execute(db, uid, object, method, *args)
+ def dispatch(self, method, auth, params):
+ (db, uid, passwd ) = params[0:3]
+ params = params[3:]
+ if method not in ['execute','exec_workflow','obj_list']:
+ raise KeyError("Method not supported %s" % method)
+ security.check(db,uid,passwd)
+ ls = netsvc.LocalService('object_proxy')
+ fn = getattr(ls, method)
+ res = fn(db, uid, *params)
return res
- def obj_list(self, db, uid, passwd):
- security.check(db, uid, passwd)
- service = netsvc.LocalService("object_proxy")
- res = service.obj_list()
- return res
+
+ def new_dispatch(self,method,auth,params):
+ pass
+
objects_proxy()
# Wizard datas: {}
# TODO: change local request to OSE request/reply pattern
#
-class wizard(netsvc.Service):
+class wizard(netsvc.ExportService):
def __init__(self, name='wizard'):
- netsvc.Service.__init__(self,name)
+ netsvc.ExportService.__init__(self,name)
self.joinGroup('web-services')
- self.exportMethod(self.execute)
- self.exportMethod(self.create)
self.id = 0
self.wiz_datas = {}
self.wiz_name = {}
self.wiz_uid = {}
+ def dispatch(self, method, auth, params):
+ (db, uid, passwd ) = params[0:3]
+ params = params[3:]
+ if method not in ['execute','create']:
+ raise KeyError("Method not supported %s" % method)
+ security.check(db,uid,passwd)
+ fn = getattr(self, 'exp_'+method)
+ res = fn(db, uid, *params)
+ return res
+
+ def new_dispatch(self,method,auth,params):
+ pass
+
def _execute(self, db, uid, wiz_id, datas, action, context):
self.wiz_datas[wiz_id].update(datas)
wiz = netsvc.LocalService('wizard.'+self.wiz_name[wiz_id])
return wiz.execute(db, uid, self.wiz_datas[wiz_id], action, context)
- def create(self, db, uid, passwd, wiz_name, datas=None):
+ def exp_create(self, db, uid, wiz_name, datas=None):
if not datas:
datas={}
- security.check(db, uid, passwd)
#FIXME: this is not thread-safe
self.id += 1
self.wiz_datas[self.id] = {}
self.wiz_uid[self.id] = uid
return self.id
- def execute(self, db, uid, passwd, wiz_id, datas, action='init', context=None):
+ def exp_execute(self, db, uid, wiz_id, datas, action='init', context=None):
if not context:
context={}
- security.check(db, uid, passwd)
if wiz_id in self.wiz_uid:
if self.wiz_uid[wiz_id] == uid:
# Report state:
# False -> True
#
-class report_spool(netsvc.Service):
+
+class ExceptionWithTraceback(Exception):
+ def __init__(self, msg, tb):
+ self.message = msg
+ self.traceback = tb
+ self.args = (msg, tb)
+
+class report_spool(netsvc.ExportService):
def __init__(self, name='report'):
- netsvc.Service.__init__(self, name)
+ netsvc.ExportService.__init__(self, name)
self.joinGroup('web-services')
- self.exportMethod(self.report)
- self.exportMethod(self.report_get)
self._reports = {}
self.id = 0
self.id_protect = threading.Semaphore()
- def report(self, db, uid, passwd, object, ids, datas=None, context=None):
+ def dispatch(self, method, auth, params):
+ (db, uid, passwd ) = params[0:3]
+ params = params[3:]
+ if method not in ['report','report_get']:
+ raise KeyError("Method not supported %s" % method)
+ security.check(db,uid,passwd)
+ fn = getattr(self, 'exp_' + method)
+ res = fn(db, uid, *params)
+ return res
+
+
+ def new_dispatch(self,method,auth,params):
+ pass
+
+ def exp_report(self, db, uid, object, ids, datas=None, context=None):
if not datas:
datas={}
if not context:
context={}
- security.check(db, uid, passwd)
self.id_protect.acquire()
self.id += 1
def go(id, uid, ids, datas, context):
cr = pooler.get_db(db).cursor()
+ import traceback
+ import sys
try:
obj = netsvc.LocalService('report.'+object)
(result, format) = obj.create(cr, uid, ids, datas, context)
+ if not result:
+ tb = sys.exc_info()
+ self._reports[id]['exception'] = ExceptionWithTraceback('RML is not available at specified location or not enough data to print!', tb)
self._reports[id]['result'] = result
self._reports[id]['format'] = format
self._reports[id]['state'] = True
except Exception, exception:
- import traceback
- import sys
- tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
- sys.exc_type, sys.exc_value, sys.exc_traceback))
+
+ tb = sys.exc_info()
+ tb_s = "".join(traceback.format_exception(*tb))
logger = netsvc.Logger()
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
'Exception: %s\n%s' % (str(exception), tb_s))
- self._reports[id]['exception'] = exception
+ self._reports[id]['exception'] = ExceptionWithTraceback(tools.exception_to_unicode(exception), tb)
self._reports[id]['state'] = True
+ cr.commit()
cr.close()
return True
del self._reports[report_id]
return res
- def report_get(self, db, uid, passwd, report_id):
- security.check(db, uid, passwd)
+ def exp_report_get(self, db, uid, report_id):
if report_id in self._reports:
if self._reports[report_id]['uid'] == uid: