From 4aacad4abf042ce706d1c8e99e734084df7163d8 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 30 Jan 2013 16:56:24 +0100 Subject: [PATCH] [REF] services: moved the report service to openerp.service.report. bzr revid: vmt@openerp.com-20130130155624-u3vfqwd3komo3wfs --- openerp/loglevels.py | 4 +- openerp/netsvc.py | 2 + openerp/service/__init__.py | 6 +- openerp/service/db.py | 10 +- openerp/service/report.py | 143 +++++++++++++++++++++++ openerp/service/web_services.py | 200 -------------------------------- 6 files changed, 152 insertions(+), 213 deletions(-) create mode 100644 openerp/service/report.py delete mode 100644 openerp/service/web_services.py diff --git a/openerp/loglevels.py b/openerp/loglevels.py index 75dca53bb6a..3172a2b2042 100644 --- a/openerp/loglevels.py +++ b/openerp/loglevels.py @@ -46,7 +46,7 @@ class Logger(object): _logger.warning( "notifyChannel API shouldn't be used anymore, please use " "the standard `logging` module instead.") - from service.web_services import common + from service import common log = logging.getLogger(__name__ + '.deprecated.' + ustr(name)) @@ -63,7 +63,7 @@ class Logger(object): try: msg = ustr(msg).strip() if level in (LOG_ERROR, LOG_CRITICAL): # and tools.config.get_misc('debug','env_info',False): - msg = common().exp_get_server_environment() + "\n" + msg + msg = common.exp_get_server_environment() + "\n" + msg result = msg.split('\n') except UnicodeDecodeError: diff --git a/openerp/netsvc.py b/openerp/netsvc.py index 374fc9a2f4d..fe0dfd06344 100644 --- a/openerp/netsvc.py +++ b/openerp/netsvc.py @@ -119,6 +119,8 @@ class ExportService(object): return openerp.service.db if name == 'common': return openerp.service.common + if name == 'report': + return openerp.service.report return cls._services[name] # Dispatch a RPC call w.r.t. the method name. The dispatching diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py index 06bf53503d7..9db73223029 100644 --- a/openerp/service/__init__.py +++ b/openerp/service/__init__.py @@ -29,8 +29,6 @@ import threading import time import cron -import web_services -import web_services import wsgi_server import openerp.modules @@ -42,6 +40,7 @@ import openerp.tools import common import db import model +import report #.apidoc title: RPC Services @@ -78,9 +77,6 @@ def start_internal(): openerp.netsvc.init_logger() openerp.modules.loading.open_openerp_namespace() - # Export (for RPC) services. - web_services.start_service() - load_server_wide_modules() start_internal_done = True diff --git a/openerp/service/db.py b/openerp/service/db.py index 2bc14084f59..2e03a56e3c3 100644 --- a/openerp/service/db.py +++ b/openerp/service/db.py @@ -204,7 +204,6 @@ def _set_pg_password_in_environment(): def exp_dump(db_name): - logger = logging.getLogger('openerp.service.web_services.db.dump') with _set_pg_password_in_environment(): cmd = ['pg_dump', '--format=c', '--no-owner'] if openerp.tools.config['db_user']: @@ -221,20 +220,19 @@ def exp_dump(db_name): res = stdout.close() if not data or res: - logger.error( + _logger.error( 'DUMP DB: %s failed! Please verify the configuration of the database password on the server. ' 'It should be provided as a -w command-line option, or as `db_password` in the ' 'server configuration file.\n %s', db_name, data) raise Exception, "Couldn't dump database" - logger.info('DUMP DB successful: %s', db_name) + _logger.info('DUMP DB successful: %s', db_name) return base64.encodestring(data) def exp_restore(db_name, data): - logger = logging.getLogger('openerp.service.web_services.db.restore') with _set_pg_password_in_environment(): if exp_db_exist(db_name): - logger.warning('RESTORE DB: %s already exists', db_name) + _logger.warning('RESTORE DB: %s already exists', db_name) raise Exception, "Database already exists" _create_empty_database(db_name) @@ -263,7 +261,7 @@ def exp_restore(db_name, data): res = stdout.close() if res: raise Exception, "Couldn't restore database" - logger.info('RESTORE DB: %s', db_name) + _logger.info('RESTORE DB: %s', db_name) return True diff --git a/openerp/service/report.py b/openerp/service/report.py new file mode 100644 index 00000000000..520faa8ead5 --- /dev/null +++ b/openerp/service/report.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- + +import logging +import threading + +import openerp.netsvc +import openerp.pooler + +_logger = logging.getLogger(__name__) + +# TODO: set a maximum report number per user to avoid DOS attacks +# +# Report state: +# False -> True + +self_reports = {} +self_id = 0 +self_id_protect = threading.Semaphore() + +def dispatch(method, params): + (db, uid, passwd ) = params[0:3] + threading.current_thread().uid = uid + params = params[3:] + if method not in ['report', 'report_get', 'render_report']: + raise KeyError("Method not supported %s" % method) + security.check(db,uid,passwd) + openerp.modules.registry.RegistryManager.check_registry_signaling(db) + fn = globals()['exp_' + method] + res = fn(db, uid, *params) + openerp.modules.registry.RegistryManager.signal_caches_change(db) + return res + +def exp_render_report(db, uid, object, ids, datas=None, context=None): + if not datas: + datas={} + if not context: + context={} + + self_id_protect.acquire() + global self_id + self_id += 1 + id = self_id + self_id_protect.release() + + self_reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} + + cr = openerp.pooler.get_db(db).cursor() + try: + obj = openerp.netsvc.LocalService('report.'+object) + (result, format) = obj.create(cr, uid, ids, datas, context) + if not result: + tb = sys.exc_info() + self_reports[id]['exception'] = openerp.exceptions.DeferredException('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: + + _logger.exception('Exception: %s\n', exception) + if hasattr(exception, 'name') and hasattr(exception, 'value'): + self_reports[id]['exception'] = openerp.exceptions.DeferredException(tools.ustr(exception.name), tools.ustr(exception.value)) + else: + tb = sys.exc_info() + self_reports[id]['exception'] = openerp.exceptions.DeferredException(tools.exception_to_unicode(exception), tb) + self_reports[id]['state'] = True + cr.commit() + cr.close() + + return _check_report(id) + +def exp_report(db, uid, object, ids, datas=None, context=None): + if not datas: + datas={} + if not context: + context={} + + self_id_protect.acquire() + global self_id + self_id += 1 + id = self_id + self_id_protect.release() + + self_reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} + + def go(id, uid, ids, datas, context): + cr = openerp.pooler.get_db(db).cursor() + try: + obj = openerp.netsvc.LocalService('report.'+object) + (result, format) = obj.create(cr, uid, ids, datas, context) + if not result: + tb = sys.exc_info() + self_reports[id]['exception'] = openerp.exceptions.DeferredException('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: + _logger.exception('Exception: %s\n', exception) + if hasattr(exception, 'name') and hasattr(exception, 'value'): + self_reports[id]['exception'] = openerp.exceptions.DeferredException(tools.ustr(exception.name), tools.ustr(exception.value)) + else: + tb = sys.exc_info() + self_reports[id]['exception'] = openerp.exceptions.DeferredException(tools.exception_to_unicode(exception), tb) + self_reports[id]['state'] = True + cr.commit() + cr.close() + return True + + thread.start_new_thread(go, (id, uid, ids, datas, context)) + return id + +def _check_report(report_id): + result = self_reports[report_id] + exc = result['exception'] + if exc: + raise openerp.osv.orm.except_orm(exc.message, exc.traceback) + res = {'state': result['state']} + if res['state']: + if tools.config['reportgz']: + import zlib + res2 = zlib.compress(result['result']) + res['code'] = 'zlib' + else: + #CHECKME: why is this needed??? + if isinstance(result['result'], unicode): + res2 = result['result'].encode('latin1', 'replace') + else: + res2 = result['result'] + if res2: + res['result'] = base64.encodestring(res2) + res['format'] = result['format'] + del self_reports[report_id] + return res + +def exp_report_get(db, uid, report_id): + if report_id in self_reports: + if self_reports[report_id]['uid'] == uid: + return _check_report(report_id) + else: + raise Exception, 'AccessDenied' + else: + raise Exception, 'ReportNotFound' + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py deleted file mode 100644 index 8c61c696723..00000000000 --- a/openerp/service/web_services.py +++ /dev/null @@ -1,200 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). -# -# This program is free software: you can redistribute it and/or modify -# 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -from __future__ import with_statement -import contextlib -import base64 -import locale -import logging -import os -import platform -import security -import sys -import thread -import threading -import time -import traceback -from cStringIO import StringIO - -from openerp.tools.translate import _ -import openerp.netsvc as netsvc -import openerp.pooler as pooler -import openerp.service.model -import openerp.sql_db as sql_db -import openerp.tools as tools -import openerp.modules -import openerp.exceptions -import openerp.osv.orm # TODO use openerp.exceptions -from openerp.service import http_server -from openerp import SUPERUSER_ID - -#.apidoc title: Exported Service methods -#.apidoc module-mods: member-order: bysource - -""" This python module defines the RPC methods available to remote clients. - - Each 'Export Service' is a group of 'methods', which in turn are RPC - procedures to be called. Each method has its own arguments footprint. -""" - -_logger = logging.getLogger(__name__) - - -# -# TODO: set a maximum report number per user to avoid DOS attacks -# -# Report state: -# False -> True -# - -class report_spool(netsvc.ExportService): - def __init__(self, name='report'): - netsvc.ExportService.__init__(self, name) - self._reports = {} - self.id = 0 - self.id_protect = threading.Semaphore() - - def dispatch(self, method, params): - (db, uid, passwd ) = params[0:3] - threading.current_thread().uid = uid - params = params[3:] - if method not in ['report', 'report_get', 'render_report']: - raise KeyError("Method not supported %s" % method) - security.check(db,uid,passwd) - openerp.modules.registry.RegistryManager.check_registry_signaling(db) - fn = getattr(self, 'exp_' + method) - res = fn(db, uid, *params) - openerp.modules.registry.RegistryManager.signal_caches_change(db) - return res - - def exp_render_report(self, db, uid, object, ids, datas=None, context=None): - if not datas: - datas={} - if not context: - context={} - - self.id_protect.acquire() - self.id += 1 - id = self.id - self.id_protect.release() - - self._reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} - - cr = pooler.get_db(db).cursor() - 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'] = openerp.exceptions.DeferredException('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: - - _logger.exception('Exception: %s\n', exception) - if hasattr(exception, 'name') and hasattr(exception, 'value'): - self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.ustr(exception.name), tools.ustr(exception.value)) - else: - tb = sys.exc_info() - self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.exception_to_unicode(exception), tb) - self._reports[id]['state'] = True - cr.commit() - cr.close() - - return self._check_report(id) - - def exp_report(self, db, uid, object, ids, datas=None, context=None): - if not datas: - datas={} - if not context: - context={} - - self.id_protect.acquire() - self.id += 1 - id = self.id - self.id_protect.release() - - self._reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} - - def go(id, uid, ids, datas, context): - cr = pooler.get_db(db).cursor() - 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'] = openerp.exceptions.DeferredException('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: - _logger.exception('Exception: %s\n', exception) - if hasattr(exception, 'name') and hasattr(exception, 'value'): - self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.ustr(exception.name), tools.ustr(exception.value)) - else: - tb = sys.exc_info() - self._reports[id]['exception'] = openerp.exceptions.DeferredException(tools.exception_to_unicode(exception), tb) - self._reports[id]['state'] = True - cr.commit() - cr.close() - return True - - thread.start_new_thread(go, (id, uid, ids, datas, context)) - return id - - def _check_report(self, report_id): - result = self._reports[report_id] - exc = result['exception'] - if exc: - raise openerp.osv.orm.except_orm(exc.message, exc.traceback) - res = {'state': result['state']} - if res['state']: - if tools.config['reportgz']: - import zlib - res2 = zlib.compress(result['result']) - res['code'] = 'zlib' - else: - #CHECKME: why is this needed??? - if isinstance(result['result'], unicode): - res2 = result['result'].encode('latin1', 'replace') - else: - res2 = result['result'] - if res2: - res['result'] = base64.encodestring(res2) - res['format'] = result['format'] - del self._reports[report_id] - return res - - def exp_report_get(self, db, uid, report_id): - if report_id in self._reports: - if self._reports[report_id]['uid'] == uid: - return self._check_report(report_id) - else: - raise Exception, 'AccessDenied' - else: - raise Exception, 'ReportNotFound' - - -def start_service(): - report_spool() - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: