remove standalone

bzr revid: al@openerp.com-20121010172418-27stgsd4w71cbxv4
This commit is contained in:
Antony Lesuisse 2012-10-10 19:24:18 +02:00
parent 5775b402a7
commit 818fd9f67f
8 changed files with 109 additions and 605 deletions

View File

@ -1,6 +1,5 @@
#!/usr/bin/python
from . import http
from . import nonliterals
from . import release
from . import session
from . import xml2json

View File

@ -6,15 +6,18 @@ import ast
import cgi
import contextlib
import functools
import getpass
import logging
import mimetypes
import os
import pprint
import sys
import tempfile
import threading
import time
import traceback
import urllib
import urlparse
import uuid
import xmlrpclib
@ -26,10 +29,10 @@ import werkzeug.utils
import werkzeug.wrappers
import werkzeug.wsgi
from . import nonliterals
from . import session
from . import openerplib
import urlparse
import openerp
import nonliterals
import session
__all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller',
'WebRequest', 'JsonRequest', 'HttpRequest']
@ -46,7 +49,6 @@ class WebRequest(object):
:param request: a wrapped werkzeug Request object
:type request: :class:`werkzeug.wrappers.BaseRequest`
:param config: configuration object
.. attribute:: httprequest
@ -58,10 +60,6 @@ class WebRequest(object):
a :class:`~collections.Mapping` holding the HTTP session data for the
current http session
.. attribute:: config
config parameter provided to the request object
.. attribute:: params
:class:`~collections.Mapping` of request parameters, not generally
@ -85,11 +83,10 @@ class WebRequest(object):
``bool``, indicates whether the debug mode is active on the client
"""
def __init__(self, request, config):
def __init__(self, request):
self.httprequest = request
self.httpresponse = None
self.httpsession = request.session
self.config = config
def init(self, params):
self.params = dict(params)
@ -98,7 +95,6 @@ class WebRequest(object):
self.session = self.httpsession.get(self.session_id)
if not self.session:
self.httpsession[self.session_id] = self.session = session.OpenERPSession()
self.session.config = self.config
self.context = self.params.pop('context', None)
self.debug = self.params.pop('debug', False) != False
@ -180,7 +176,7 @@ class JsonRequest(WebRequest):
_logger.debug("--> %s.%s\n%s", controller.__class__.__name__, method.__name__, pprint.pformat(self.jsonrequest))
response['id'] = self.jsonrequest.get('id')
response["result"] = method(controller, self, **self.params)
except openerplib.AuthenticationError:
except session.AuthenticationError:
error = {
'code': 100,
'message': "OpenERP Session Invalid",
@ -238,8 +234,8 @@ def jsonrequest(f):
beforehand)
"""
@functools.wraps(f)
def json_handler(controller, request, config):
return JsonRequest(request, config).dispatch(controller, f)
def json_handler(controller, request):
return JsonRequest(request).dispatch(controller, f)
json_handler.exposed = True
return json_handler
@ -325,8 +321,8 @@ def httprequest(f):
and ``debug`` keys (which are stripped out beforehand)
"""
@functools.wraps(f)
def http_handler(controller, request, config):
return HttpRequest(request, config).dispatch(controller, f)
def http_handler(controller, request):
return HttpRequest(request).dispatch(controller, f)
http_handler.exposed = True
return http_handler
@ -425,6 +421,7 @@ def session_context(request, storage_path, session_cookie='httpsessionid'):
mimetypes.add_type('application/font-woff', '.woff')
mimetypes.add_type('application/vnd.ms-fontobject', '.eot')
mimetypes.add_type('application/x-font-ttf', '.ttf')
class DisableCacheMiddleware(object):
def __init__(self, app):
self.app = app
@ -449,45 +446,23 @@ class DisableCacheMiddleware(object):
class Root(object):
"""Root WSGI application for the OpenERP Web Client.
:param options: mandatory initialization options object, must provide
the following attributes:
``server_host`` (``str``)
hostname of the OpenERP server to dispatch RPC to
``server_port`` (``int``)
RPC port of the OpenERP server
``serve_static`` (``bool | None``)
whether this application should serve the various
addons's static files
``storage_path`` (``str``)
filesystem path where HTTP session data will be stored
``dbfilter`` (``str``)
only used in case the list of databases is requested
by the server, will be filtered by this pattern
"""
def __init__(self, options):
self.config = options
if not hasattr(self.config, 'connector'):
if self.config.backend == 'local':
self.config.connector = session.LocalConnector()
else:
self.config.connector = openerplib.get_connector(
hostname=self.config.server_host, port=self.config.server_port)
def __init__(self):
self.httpsession_cookie = 'httpsessionid'
self.addons = {}
static_dirs = self._load_addons()
if options.serve_static:
app = werkzeug.wsgi.SharedDataMiddleware( self.dispatch, static_dirs)
self.dispatch = DisableCacheMiddleware(app)
app = werkzeug.wsgi.SharedDataMiddleware( self.dispatch, static_dirs)
self.dispatch = DisableCacheMiddleware(app)
if options.session_storage:
if not os.path.exists(options.session_storage):
os.mkdir(options.session_storage, 0700)
self.session_storage = options.session_storage
try:
username = getpass.getuser()
except Exception:
username = "unknown"
self.session_storage = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
if not os.path.exists(self.session_storage):
os.mkdir(self.session_storage, 0700)
_logger.debug('HTTP sessions stored in: %s', self.session_storage)
def __call__(self, environ, start_response):
@ -512,7 +487,7 @@ class Root(object):
response = werkzeug.exceptions.NotFound()
else:
with session_context(request, self.session_storage, self.httpsession_cookie) as session:
result = handler( request, self.config)
result = handler( request)
if isinstance(result, basestring):
headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))]
@ -531,7 +506,7 @@ class Root(object):
static URLs to the corresponding directories
"""
statics = {}
for addons_path in self.config.addons_path:
for addons_path in openerp.modules.module.ad_paths:
for module in os.listdir(addons_path):
if module not in addons_module:
manifest_path = os.path.join(addons_path, module, '__openerp__.py')
@ -579,28 +554,8 @@ class Root(object):
ps = '/'
return None
class Options(object):
pass
def wsgi_postload():
import openerp
import tempfile
import getpass
_logger.info("embedded mode")
o = Options()
o.dbfilter = openerp.tools.config['dbfilter']
o.server_wide_modules = openerp.conf.server_wide_modules or ['web']
try:
username = getpass.getuser()
except Exception:
username = "unknown"
o.session_storage = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
o.addons_path = openerp.modules.module.ad_paths
o.serve_static = True
o.backend = 'local'
app = Root(o)
openerp.wsgi.register_wsgi_handler(app)
openerp.wsgi.register_wsgi_handler(Root())
# vim:et:ts=4:sw=4:

View File

@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) Stephane Wirtel
# Copyright (C) 2011 Nicolas Vanhoren
# Copyright (C) 2011 OpenERP s.a. (<http://openerp.com>).
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##############################################################################
from .main import *

View File

@ -1,97 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) Stephane Wirtel
# Copyright (C) 2011 Nicolas Vanhoren
# Copyright (C) 2011 OpenERP s.a. (<http://openerp.com>).
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##############################################################################
import datetime
DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d"
DEFAULT_SERVER_TIME_FORMAT = "%H:%M:%S"
DEFAULT_SERVER_DATETIME_FORMAT = "%s %s" % (
DEFAULT_SERVER_DATE_FORMAT,
DEFAULT_SERVER_TIME_FORMAT)
def str_to_datetime(str):
"""
Converts a string to a datetime object using OpenERP's
datetime string format (exemple: '2011-12-01 15:12:35').
No timezone information is added, the datetime is a naive instance, but
according to OpenERP 6.1 specification the timezone is always UTC.
"""
if not str:
return str
return datetime.datetime.strptime(str, DEFAULT_SERVER_DATETIME_FORMAT)
def str_to_date(str):
"""
Converts a string to a date object using OpenERP's
date string format (exemple: '2011-12-01').
"""
if not str:
return str
return datetime.datetime.strptime(str, DEFAULT_SERVER_DATE_FORMAT).date()
def str_to_time(str):
"""
Converts a string to a time object using OpenERP's
time string format (exemple: '15:12:35').
"""
if not str:
return str
return datetime.datetime.strptime(str, DEFAULT_SERVER_TIME_FORMAT).time()
def datetime_to_str(obj):
"""
Converts a datetime object to a string using OpenERP's
datetime string format (exemple: '2011-12-01 15:12:35').
The datetime instance should not have an attached timezone and be in UTC.
"""
if not obj:
return False
return obj.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
def date_to_str(obj):
"""
Converts a date object to a string using OpenERP's
date string format (exemple: '2011-12-01').
"""
if not obj:
return False
return obj.strftime(DEFAULT_SERVER_DATE_FORMAT)
def time_to_str(obj):
"""
Converts a time object to a string using OpenERP's
time string format (exemple: '15:12:35').
"""
if not obj:
return False
return obj.strftime(DEFAULT_SERVER_TIME_FORMAT)

View File

@ -1,311 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) Stephane Wirtel
# Copyright (C) 2011 Nicolas Vanhoren
# Copyright (C) 2011 OpenERP s.a. (<http://openerp.com>).
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##############################################################################
"""
OpenERP Client Library
Home page: http://pypi.python.org/pypi/openerp-client-lib
Code repository: https://code.launchpad.net/~niv-openerp/openerp-client-lib/trunk
"""
import xmlrpclib
import logging
_logger = logging.getLogger(__name__)
def _getChildLogger(logger, subname):
return logging.getLogger(logger.name + "." + subname)
class Connector(object):
"""
The base abstract class representing a connection to an OpenERP Server.
"""
__logger = _getChildLogger(_logger, 'connector')
def get_service(self, service_name):
"""
Returns a Service instance to allow easy manipulation of one of the services offered by the remote server.
:param service_name: The name of the service.
"""
return Service(self, service_name)
class XmlRPCConnector(Connector):
"""
A type of connector that uses the XMLRPC protocol.
"""
PROTOCOL = 'xmlrpc'
__logger = _getChildLogger(_logger, 'connector.xmlrpc')
def __init__(self, hostname, port=8069):
"""
Initialize by specifying the hostname and the port.
:param hostname: The hostname of the computer holding the instance of OpenERP.
:param port: The port used by the OpenERP instance for XMLRPC (default to 8069).
"""
self.url = 'http://%s:%d/xmlrpc' % (hostname, port)
def send(self, service_name, method, *args):
url = '%s/%s' % (self.url, service_name)
service = xmlrpclib.ServerProxy(url)
return getattr(service, method)(*args)
class XmlRPCSConnector(XmlRPCConnector):
"""
A type of connector that uses the secured XMLRPC protocol.
"""
PROTOCOL = 'xmlrpcs'
__logger = _getChildLogger(_logger, 'connector.xmlrpcs')
def __init__(self, hostname, port=8069):
super(XmlRPCSConnector, self).__init__(hostname, port)
self.url = 'https://%s:%d/xmlrpc' % (hostname, port)
class Service(object):
"""
A class to execute RPC calls on a specific service of the remote server.
"""
def __init__(self, connector, service_name):
"""
:param connector: A valid Connector instance.
:param service_name: The name of the service on the remote server.
"""
self.connector = connector
self.service_name = service_name
self.__logger = _getChildLogger(_getChildLogger(_logger, 'service'),service_name or "")
def __getattr__(self, method):
"""
:param method: The name of the method to execute on the service.
"""
self.__logger.debug('method: %r', method)
def proxy(*args):
"""
:param args: A list of values for the method
"""
self.__logger.debug('args: %r', args)
result = self.connector.send(self.service_name, method, *args)
self.__logger.debug('result: %r', result)
return result
return proxy
class Connection(object):
"""
A class to represent a connection with authentication to an OpenERP Server.
It also provides utility methods to interact with the server more easily.
"""
__logger = _getChildLogger(_logger, 'connection')
def __init__(self, connector,
database=None,
login=None,
password=None,
user_id=None):
"""
Initialize with login information. The login information is facultative to allow specifying
it after the initialization of this object.
:param connector: A valid Connector instance to send messages to the remote server.
:param database: The name of the database to work on.
:param login: The login of the user.
:param password: The password of the user.
:param user_id: The user id is a number identifying the user. This is only useful if you
already know it, in most cases you don't need to specify it.
"""
self.connector = connector
self.set_login_info(database, login, password, user_id)
self.user_context = None
def set_login_info(self, database, login, password, user_id=None):
"""
Set login information after the initialisation of this object.
:param connector: A valid Connector instance to send messages to the remote server.
:param database: The name of the database to work on.
:param login: The login of the user.
:param password: The password of the user.
:param user_id: The user id is a number identifying the user. This is only useful if you
already know it, in most cases you don't need to specify it.
"""
self.database, self.login, self.password = database, login, password
self.user_id = user_id
def check_login(self, force=True):
"""
Checks that the login information is valid. Throws an AuthenticationError if the
authentication fails.
:param force: Force to re-check even if this Connection was already validated previously.
Default to True.
"""
if self.user_id and not force:
return
if not self.database or not self.login or self.password is None:
raise AuthenticationError("Credentials not provided")
# TODO use authenticate instead of login
self.user_id = self.get_service("common").login(self.database, self.login, self.password)
if not self.user_id:
raise AuthenticationError("Authentication failure")
self.__logger.debug("Authenticated with user id %s", self.user_id)
def get_user_context(self):
"""
Query the default context of the user.
"""
if not self.user_context:
self.user_context = self.get_model('res.users').context_get()
return self.user_context
def get_model(self, model_name):
"""
Returns a Model instance to allow easy remote manipulation of an OpenERP model.
:param model_name: The name of the model.
"""
return Model(self, model_name)
def get_service(self, service_name):
"""
Returns a Service instance to allow easy manipulation of one of the services offered by the remote server.
Please note this Connection instance does not need to have valid authentication information since authentication
is only necessary for the "object" service that handles models.
:param service_name: The name of the service.
"""
return self.connector.get_service(service_name)
class AuthenticationError(Exception):
"""
An error thrown when an authentication to an OpenERP server failed.
"""
pass
class Model(object):
"""
Useful class to dialog with one of the models provided by an OpenERP server.
An instance of this class depends on a Connection instance with valid authentication information.
"""
def __init__(self, connection, model_name):
"""
:param connection: A valid Connection instance with correct authentication information.
:param model_name: The name of the model.
"""
self.connection = connection
self.model_name = model_name
self.__logger = _getChildLogger(_getChildLogger(_logger, 'object'), model_name or "")
def __getattr__(self, method):
"""
Provides proxy methods that will forward calls to the model on the remote OpenERP server.
:param method: The method for the linked model (search, read, write, unlink, create, ...)
"""
def proxy(*args, **kw):
"""
:param args: A list of values for the method
"""
self.connection.check_login(False)
self.__logger.debug(args)
result = self.connection.get_service('object').execute_kw(
self.connection.database,
self.connection.user_id,
self.connection.password,
self.model_name,
method,
args, kw)
if method == "read":
if isinstance(result, list) and len(result) > 0 and "id" in result[0]:
index = {}
for r in result:
index[r['id']] = r
result = [index[x] for x in args[0] if x in index]
self.__logger.debug('result: %r', result)
return result
return proxy
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None, context=None):
"""
A shortcut method to combine a search() and a read().
:param domain: The domain for the search.
:param fields: The fields to extract (can be None or [] to extract all fields).
:param offset: The offset for the rows to read.
:param limit: The maximum number of rows to read.
:param order: The order to class the rows.
:param context: The context.
:return: A list of dictionaries containing all the specified fields.
"""
record_ids = self.search(domain or [], offset, limit or False, order or False, context or {})
if not record_ids: return []
records = self.read(record_ids, fields or [], context or {})
return records
def get_connector(hostname=None, protocol="xmlrpc", port="auto"):
"""
A shortcut method to easily create a connector to a remote server using XMLRPC.
:param hostname: The hostname to the remote server.
:param protocol: The name of the protocol, must be "xmlrpc" or "xmlrpcs".
:param port: The number of the port. Defaults to auto.
"""
if port == 'auto':
port = 8069
if protocol == "xmlrpc":
return XmlRPCConnector(hostname, port)
elif protocol == "xmlrpcs":
return XmlRPCSConnector(hostname, port)
else:
raise ValueError("You must choose xmlrpc or xmlrpcs")
def get_connection(hostname=None, protocol="xmlrpc", port='auto', database=None,
login=None, password=None, user_id=None):
"""
A shortcut method to easily create a connection to a remote OpenERP server.
:param hostname: The hostname to the remote server.
:param protocol: The name of the protocol, must be "xmlrpc" or "xmlrpcs".
:param port: The number of the port. Defaults to auto.
:param connector: A valid Connector instance to send messages to the remote server.
:param database: The name of the database to work on.
:param login: The login of the user.
:param password: The password of the user.
:param user_id: The user id is a number identifying the user. This is only useful if you
already know it, in most cases you don't need to specify it.
"""
return Connection(get_connector(hostname, protocol, port), database, login, password, user_id)

View File

@ -1,10 +0,0 @@
name = 'openerp-web'
version = '7.0alpha'
description = "OpenERP Web"
long_description = "OpenERP Web is the web interface of OpenERP, an Open Source Business Application Suite"
author = "OpenERP SA"
author_email = "info@openerp.com"
support_email = 'support@openerp.com'
url = "http://www.openerp.com/"
download_url = ''
license = "AGPL"

View File

@ -4,70 +4,58 @@ import babel
import dateutil.relativedelta
import logging
import time
import traceback
import sys
import xmlrpclib
import openerplib
import openerp
from . import nonliterals
import nonliterals
_logger = logging.getLogger(__name__)
#----------------------------------------------------------
# openerplib local connector
#----------------------------------------------------------
class LibException(Exception):
""" Base of all client lib exceptions """
def __init__(self,code=None,message=None):
self.code = code
self.message = message
class ApplicationError(LibException):
""" maps to code: 1, server side: Exception or openerp.exceptions.DeferredException"""
class Warning(LibException):
""" maps to code: 2, server side: openerp.exceptions.Warning"""
class AccessError(LibException):
""" maps to code: 3, server side: openerp.exceptions.AccessError"""
class AccessDenied(LibException):
""" maps to code: 4, server side: openerp.exceptions.AccessDenied"""
class LocalConnector(openerplib.Connector):
"""
A type of connector that uses the XMLRPC protocol.
"""
PROTOCOL = 'local'
def __init__(self):
pass
def send(self, service_name, method, *args):
import openerp
import traceback
import xmlrpclib
code_string = "warning -- %s\n\n%s"
try:
return openerp.netsvc.dispatch_rpc(service_name, method, args)
except openerp.osv.osv.except_osv, e:
# TODO change the except to raise LibException instead of their emulated xmlrpc fault
raise xmlrpclib.Fault(code_string % (e.name, e.value), '')
except openerp.exceptions.Warning, e:
raise xmlrpclib.Fault(code_string % ("Warning", e), '')
except openerp.exceptions.AccessError, e:
raise xmlrpclib.Fault(code_string % ("AccessError", e), '')
except openerp.exceptions.AccessDenied, e:
raise xmlrpclib.Fault('AccessDenied', str(e))
except openerp.exceptions.DeferredException, e:
formatted_info = "".join(traceback.format_exception(*e.traceback))
raise xmlrpclib.Fault(openerp.tools.ustr(e.message), formatted_info)
except Exception, e:
formatted_info = "".join(traceback.format_exception(*(sys.exc_info())))
raise xmlrpclib.Fault(openerp.tools.exception_to_unicode(e), formatted_info)
#----------------------------------------------------------
# OpenERPSession RPC openerp backend access
#----------------------------------------------------------
class AuthenticationError(Exception):
pass
class Service(object):
def __init__(self, session, service_name):
self.session = session
self.service_name = service_name
def __getattr__(self, method):
def proxy_method(*args):
result = self.session.send(self.service_name, method, *args)
return result
return proxy_method
class Model(object):
def __init__(self, session, model):
self.session = session
self.model = model
self.proxy = self.session.proxy('object')
def __getattr__(self, method):
def proxy(*args, **kw):
result = self.proxy.execute_kw(self.session._db, self.session._uid, self.session._password, self.model, method, args, kw)
# reorder read
if method == "read":
if isinstance(result, list) and len(result) > 0 and "id" in result[0]:
index = {}
for r in result:
index[r['id']] = r
result = [index[x] for x in args[0] if x in index]
return result
return proxy
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None, context=None):
record_ids = self.search(domain or [], offset, limit or False, order or False, context or {})
if not record_ids: return []
records = self.read(record_ids, fields or [], context or {})
return records
class OpenERPSession(object):
"""
An OpenERP RPC session, a given user can own multiple such sessions
@ -87,7 +75,6 @@ class OpenERPSession(object):
"""
def __init__(self):
self._creation_time = time.time()
self.config = None
self._db = False
self._uid = False
self._login = False
@ -98,19 +85,27 @@ class OpenERPSession(object):
self.domains_store = {}
self.jsonp_requests = {} # FIXME use a LRU
def __getstate__(self):
state = dict(self.__dict__)
if "config" in state:
del state['config']
return state
def build_connection(self):
conn = openerplib.Connection(self.config.connector, database=self._db, login=self._login,
user_id=self._uid, password=self._password)
return conn
def send(self, service_name, method, *args):
code_string = "warning -- %s\n\n%s"
try:
return openerp.netsvc.dispatch_rpc(service_name, method, args)
except openerp.osv.osv.except_osv, e:
raise xmlrpclib.Fault(code_string % (e.name, e.value), '')
except openerp.exceptions.Warning, e:
raise xmlrpclib.Fault(code_string % ("Warning", e), '')
except openerp.exceptions.AccessError, e:
raise xmlrpclib.Fault(code_string % ("AccessError", e), '')
except openerp.exceptions.AccessDenied, e:
raise xmlrpclib.Fault('AccessDenied', str(e))
except openerp.exceptions.DeferredException, e:
formatted_info = "".join(traceback.format_exception(*e.traceback))
raise xmlrpclib.Fault(openerp.tools.ustr(e.message), formatted_info)
except Exception, e:
formatted_info = "".join(traceback.format_exception(*(sys.exc_info())))
raise xmlrpclib.Fault(openerp.tools.exception_to_unicode(e), formatted_info)
def proxy(self, service):
return self.build_connection().get_service(service)
return Service(self, service)
def bind(self, db, uid, login, password):
self._db = db
@ -119,7 +114,6 @@ class OpenERPSession(object):
self._password = password
def authenticate(self, db, login, password, env=None):
# TODO use the openerplib API once it exposes authenticate()
uid = self.proxy('common').authenticate(db, login, password, env)
self.bind(db, uid, login, password)
@ -130,7 +124,12 @@ class OpenERPSession(object):
"""
Ensures this session is valid (logged into the openerp server)
"""
self.build_connection().check_login(force)
if self._uid and not force:
return
# TODO use authenticate instead of login
uid = self.proxy("common").login(self._db, self._login, self._password)
if not uid:
raise AuthenticationError("Authentication failure")
def ensure_valid(self):
if self._uid:
@ -141,7 +140,7 @@ class OpenERPSession(object):
def execute(self, model, func, *l, **d):
self.assert_valid()
model = self.build_connection().get_model(model)
model = self.model(model)
r = getattr(model, func)(*l, **d)
return r
@ -157,7 +156,8 @@ class OpenERPSession(object):
:type model: str
:rtype: a model object
"""
return self.build_connection().get_model(model)
return Model(self, model)
def get_context(self):
""" Re-initializes the current user's session context (based on
@ -167,7 +167,7 @@ class OpenERPSession(object):
:returns: the new context
"""
assert self._uid, "The user needs to be logged-in to initialize his context"
self.context = self.build_connection().get_user_context() or {}
self.context = self.model('res.users').context_get() or {}
self.context['uid'] = self._uid
self._fix_lang(self.context)
return self.context

View File

@ -27,6 +27,8 @@ try:
except ImportError:
xlwt = None
import openerp
from .. import common
openerpweb = common.http
@ -135,7 +137,7 @@ def db_list(req):
dbs = proxy.list()
h = req.httprequest.environ['HTTP_HOST'].split(':')[0]
d = h.split('.')[0]
r = req.config.dbfilter.replace('%h', h).replace('%d', d)
r = openerp.tools.config['dbfilter'].replace('%h', h).replace('%d', d)
dbs = [i for i in dbs if re.match(r, i)]
return dbs
@ -227,11 +229,12 @@ def module_installed_bypass_session(dbname):
return sorted_modules
def module_boot(req):
return [m for m in req.config.server_wide_modules if m in openerpweb.addons_manifest]
server_wide_modules = openerp.conf.server_wide_modules or ['web']
return [m for m in server_wide_modules if m in openerpweb.addons_manifest]
# TODO the following will be enabled once we separate the module code and translation loading
serverside = []
dbside = []
for i in req.config.server_wide_modules:
for i in server_wide_modules:
if i in openerpweb.addons_manifest:
serverside.append(i)
# if only one db load every module at boot
@ -507,7 +510,7 @@ def parse_domain(domain, session):
:param domain: the domain to parse, if the domain is not a string it
is assumed to be a literal domain and is returned as-is
:param session: Current OpenERP session
:type session: openerpweb.openerpweb.OpenERPSession
:type session: openerpweb.OpenERPSession
"""
if not isinstance(domain, basestring):
return domain
@ -524,7 +527,7 @@ def parse_context(context, session):
:param context: the context to parse, if the context is not a string it
is assumed to be a literal domain and is returned as-is
:param session: Current OpenERP session
:type session: openerpweb.openerpweb.OpenERPSession
:type session: openerpweb.OpenERPSession
"""
if not isinstance(context, basestring):
return context
@ -612,7 +615,6 @@ class Home(openerpweb.Controller):
def login(self, req, db, login, key):
return login_and_redirect(req, db, login, key)
class WebClient(openerpweb.Controller):
_cp_path = "/web/webclient"
@ -746,7 +748,7 @@ class WebClient(openerpweb.Controller):
@openerpweb.jsonrequest
def version_info(self, req):
return {
"version": common.release.version
"version": openerp.release.version
}
class Proxy(openerpweb.Controller):
@ -862,12 +864,10 @@ class Session(openerpweb.Controller):
@openerpweb.jsonrequest
def authenticate(self, req, db, login, password, base_location=None):
wsgienv = req.httprequest.environ
release = common.release
env = dict(
base_location=base_location,
HTTP_HOST=wsgienv['HTTP_HOST'],
REMOTE_ADDR=wsgienv['REMOTE_ADDR'],
user_agent="%s / %s" % (release.name, release.version),
)
req.session.authenticate(db, login, password, env)