summaryrefslogtreecommitdiff
path: root/addons/web/common
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/common')
-rw-r--r--addons/web/common/__init__.py6
-rw-r--r--addons/web/common/http.py582
-rw-r--r--addons/web/common/nonliterals.py267
-rw-r--r--addons/web/common/openerplib/__init__.py32
-rw-r--r--addons/web/common/openerplib/dates.py97
-rw-r--r--addons/web/common/openerplib/main.py311
-rw-r--r--addons/web/common/release.py10
-rw-r--r--addons/web/common/session.py270
-rw-r--r--addons/web/common/xml2json.py26
9 files changed, 0 insertions, 1601 deletions
diff --git a/addons/web/common/__init__.py b/addons/web/common/__init__.py
deleted file mode 100644
index 4060be2f87e..00000000000
--- a/addons/web/common/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/python
-from . import http
-from . import nonliterals
-from . import release
-from . import session
-from . import xml2json
diff --git a/addons/web/common/http.py b/addons/web/common/http.py
deleted file mode 100644
index 4955876894d..00000000000
--- a/addons/web/common/http.py
+++ /dev/null
@@ -1,582 +0,0 @@
-# -*- coding: utf-8 -*-
-#----------------------------------------------------------
-# OpenERP Web HTTP layer
-#----------------------------------------------------------
-import ast
-import cgi
-import contextlib
-import functools
-import logging
-import mimetypes
-import os
-import pprint
-import sys
-import threading
-import time
-import traceback
-import urllib
-import uuid
-import xmlrpclib
-
-import simplejson
-import werkzeug.contrib.sessions
-import werkzeug.datastructures
-import werkzeug.exceptions
-import werkzeug.utils
-import werkzeug.wrappers
-import werkzeug.wsgi
-
-from . import nonliterals
-from . import session
-from . import openerplib
-import urlparse
-
-__all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller',
- 'WebRequest', 'JsonRequest', 'HttpRequest']
-
-_logger = logging.getLogger(__name__)
-
-#----------------------------------------------------------
-# OpenERP Web RequestHandler
-#----------------------------------------------------------
-class WebRequest(object):
- """ Parent class for all OpenERP Web request types, mostly deals with
- initialization and setup of the request object (the dispatching itself has
- to be handled by the subclasses)
-
- :param request: a wrapped werkzeug Request object
- :type request: :class:`werkzeug.wrappers.BaseRequest`
- :param config: configuration object
-
- .. attribute:: httprequest
-
- the original :class:`werkzeug.wrappers.Request` object provided to the
- request
-
- .. attribute:: httpsession
-
- 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
- useful as they're provided directly to the handler method as keyword
- arguments
-
- .. attribute:: session_id
-
- opaque identifier for the :class:`session.OpenERPSession` instance of
- the current request
-
- .. attribute:: session
-
- :class:`~session.OpenERPSession` instance for the current request
-
- .. attribute:: context
-
- :class:`~collections.Mapping` of context values for the current request
-
- .. attribute:: debug
-
- ``bool``, indicates whether the debug mode is active on the client
- """
- def __init__(self, request, config):
- self.httprequest = request
- self.httpresponse = None
- self.httpsession = request.session
- self.config = config
-
- def init(self, params):
- self.params = dict(params)
- # OpenERP session setup
- self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex
- 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
-
-class JsonRequest(WebRequest):
- """ JSON-RPC2 over HTTP.
-
- Sucessful request::
-
- --> {"jsonrpc": "2.0",
- "method": "call",
- "params": {"session_id": "SID",
- "context": {},
- "arg1": "val1" },
- "id": null}
-
- <-- {"jsonrpc": "2.0",
- "result": { "res1": "val1" },
- "id": null}
-
- Request producing a error::
-
- --> {"jsonrpc": "2.0",
- "method": "call",
- "params": {"session_id": "SID",
- "context": {},
- "arg1": "val1" },
- "id": null}
-
- <-- {"jsonrpc": "2.0",
- "error": {"code": 1,
- "message": "End user error message.",
- "data": {"code": "codestring",
- "debug": "traceback" } },
- "id": null}
-
- """
- def dispatch(self, controller, method):
- """ Calls the method asked for by the JSON-RPC2 or JSONP request
-
- :param controller: the instance of the controller which received the request
- :param method: the method which received the request
-
- :returns: an utf8 encoded JSON-RPC2 or JSONP reply
- """
- args = self.httprequest.args
- jsonp = args.get('jsonp')
- requestf = None
- request = None
- request_id = args.get('id')
-
- if jsonp and self.httprequest.method == 'POST':
- # jsonp 2 steps step1 POST: save call
- self.init(args)
- self.session.jsonp_requests[request_id] = self.httprequest.form['r']
- headers=[('Content-Type', 'text/plain; charset=utf-8')]
- r = werkzeug.wrappers.Response(request_id, headers=headers)
- return r
- elif jsonp and args.get('r'):
- # jsonp method GET
- request = args.get('r')
- elif jsonp and request_id:
- # jsonp 2 steps step2 GET: run and return result
- self.init(args)
- request = self.session.jsonp_requests.pop(request_id, "")
- else:
- # regular jsonrpc2
- requestf = self.httprequest.stream
-
- response = {"jsonrpc": "2.0" }
- error = None
- try:
- # Read POST content or POST Form Data named "request"
- if requestf:
- self.jsonrequest = simplejson.load(requestf, object_hook=nonliterals.non_literal_decoder)
- else:
- self.jsonrequest = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder)
- self.init(self.jsonrequest.get("params", {}))
- if _logger.isEnabledFor(logging.DEBUG):
- _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:
- error = {
- 'code': 100,
- 'message': "OpenERP Session Invalid",
- 'data': {
- 'type': 'session_invalid',
- 'debug': traceback.format_exc()
- }
- }
- except xmlrpclib.Fault, e:
- error = {
- 'code': 200,
- 'message': "OpenERP Server Error",
- 'data': {
- 'type': 'server_exception',
- 'fault_code': e.faultCode,
- 'debug': "Client %s\nServer %s" % (
- "".join(traceback.format_exception("", None, sys.exc_traceback)), e.faultString)
- }
- }
- except Exception:
- logging.getLogger(__name__ + '.JSONRequest.dispatch').exception\
- ("An error occured while handling a json request")
- error = {
- 'code': 300,
- 'message': "OpenERP WebClient Error",
- 'data': {
- 'type': 'client_exception',
- 'debug': "Client %s" % traceback.format_exc()
- }
- }
- if error:
- response["error"] = error
-
- if _logger.isEnabledFor(logging.DEBUG):
- _logger.debug("<--\n%s", pprint.pformat(response))
-
- if jsonp:
- mime = 'application/javascript'
- body = "%s(%s);" % (jsonp, simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder),)
- else:
- mime = 'application/json'
- body = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder)
-
- r = werkzeug.wrappers.Response(body, headers=[('Content-Type', mime), ('Content-Length', len(body))])
- return r
-
-def jsonrequest(f):
- """ Decorator marking the decorated method as being a handler for a
- JSON-RPC request (the exact request path is specified via the
- ``$(Controller._cp_path)/$methodname`` combination.
-
- If the method is called, it will be provided with a :class:`JsonRequest`
- instance and all ``params`` sent during the JSON-RPC request, apart from
- the ``session_id``, ``context`` and ``debug`` keys (which are stripped out
- beforehand)
- """
- @functools.wraps(f)
- def json_handler(controller, request, config):
- return JsonRequest(request, config).dispatch(controller, f)
- json_handler.exposed = True
- return json_handler
-
-class HttpRequest(WebRequest):
- """ Regular GET/POST request
- """
- def dispatch(self, controller, method):
- params = dict(self.httprequest.args)
- params.update(self.httprequest.form)
- params.update(self.httprequest.files)
- self.init(params)
- akw = {}
- for key, value in self.httprequest.args.iteritems():
- if isinstance(value, basestring) and len(value) < 1024:
- akw[key] = value
- else:
- akw[key] = type(value)
- _logger.debug("%s --> %s.%s %r", self.httprequest.method, controller.__class__.__name__, method.__name__, akw)
- try:
- r = method(controller, self, **self.params)
- except xmlrpclib.Fault, e:
- r = werkzeug.exceptions.InternalServerError(cgi.escape(simplejson.dumps({
- 'code': 200,
- 'message': "OpenERP Server Error",
- 'data': {
- 'type': 'server_exception',
- 'fault_code': e.faultCode,
- 'debug': "Server %s\nClient %s" % (
- e.faultString, traceback.format_exc())
- }
- })))
- except Exception:
- logging.getLogger(__name__ + '.HttpRequest.dispatch').exception(
- "An error occurred while handling a json request")
- r = werkzeug.exceptions.InternalServerError(cgi.escape(simplejson.dumps({
- 'code': 300,
- 'message': "OpenERP WebClient Error",
- 'data': {
- 'type': 'client_exception',
- 'debug': "Client %s" % traceback.format_exc()
- }
- })))
- if self.debug or 1:
- if isinstance(r, (werkzeug.wrappers.BaseResponse, werkzeug.exceptions.HTTPException)):
- _logger.debug('<-- %s', r)
- else:
- _logger.debug("<-- size: %s", len(r))
- return r
-
- def make_response(self, data, headers=None, cookies=None):
- """ Helper for non-HTML responses, or HTML responses with custom
- response headers or cookies.
-
- While handlers can just return the HTML markup of a page they want to
- send as a string if non-HTML data is returned they need to create a
- complete response object, or the returned data will not be correctly
- interpreted by the clients.
-
- :param basestring data: response body
- :param headers: HTTP headers to set on the response
- :type headers: ``[(name, value)]``
- :param collections.Mapping cookies: cookies to set on the client
- """
- response = werkzeug.wrappers.Response(data, headers=headers)
- if cookies:
- for k, v in cookies.iteritems():
- response.set_cookie(k, v)
- return response
-
- def not_found(self, description=None):
- """ Helper for 404 response, return its result from the method
- """
- return werkzeug.exceptions.NotFound(description)
-
-def httprequest(f):
- """ Decorator marking the decorated method as being a handler for a
- normal HTTP request (the exact request path is specified via the
- ``$(Controller._cp_path)/$methodname`` combination.
-
- If the method is called, it will be provided with a :class:`HttpRequest`
- instance and all ``params`` sent during the request (``GET`` and ``POST``
- merged in the same dictionary), apart from the ``session_id``, ``context``
- and ``debug`` keys (which are stripped out beforehand)
- """
- @functools.wraps(f)
- def http_handler(controller, request, config):
- return HttpRequest(request, config).dispatch(controller, f)
- http_handler.exposed = True
- return http_handler
-
-#----------------------------------------------------------
-# OpenERP Web Controller registration with a metaclass
-#----------------------------------------------------------
-addons_module = {}
-addons_manifest = {}
-controllers_class = []
-controllers_object = {}
-controllers_path = {}
-
-class ControllerType(type):
- def __init__(cls, name, bases, attrs):
- super(ControllerType, cls).__init__(name, bases, attrs)
- controllers_class.append(("%s.%s" % (cls.__module__, cls.__name__), cls))
-
-class Controller(object):
- __metaclass__ = ControllerType
-
-#----------------------------------------------------------
-# OpenERP Web Session context manager
-#----------------------------------------------------------
-STORES = {}
-
-@contextlib.contextmanager
-def session_context(request, storage_path, session_cookie='httpsessionid'):
- session_store, session_lock = STORES.get(storage_path, (None, None))
- if not session_store:
- session_store = werkzeug.contrib.sessions.FilesystemSessionStore( storage_path)
- session_lock = threading.Lock()
- STORES[storage_path] = session_store, session_lock
-
- sid = request.cookies.get(session_cookie)
- with session_lock:
- if sid:
- request.session = session_store.get(sid)
- else:
- request.session = session_store.new()
-
- try:
- yield request.session
- finally:
- # Remove all OpenERPSession instances with no uid, they're generated
- # either by login process or by HTTP requests without an OpenERP
- # session id, and are generally noise
- removed_sessions = set()
- for key, value in request.session.items():
- if not isinstance(value, session.OpenERPSession):
- continue
- if getattr(value, '_suicide', False) or (
- not value._uid
- and not value.jsonp_requests
- # FIXME do not use a fixed value
- and value._creation_time + (60*5) < time.time()):
- _logger.debug('remove session %s', key)
- removed_sessions.add(key)
- del request.session[key]
-
- with session_lock:
- if sid:
- # Re-load sessions from storage and merge non-literal
- # contexts and domains (they're indexed by hash of the
- # content so conflicts should auto-resolve), otherwise if
- # two requests alter those concurrently the last to finish
- # will overwrite the previous one, leading to loss of data
- # (a non-literal is lost even though it was sent to the
- # client and client errors)
- #
- # note that domains_store and contexts_store are append-only (we
- # only ever add items to them), so we can just update one with the
- # other to get the right result, if we want to merge the
- # ``context`` dict we'll need something smarter
- in_store = session_store.get(sid)
- for k, v in request.session.iteritems():
- stored = in_store.get(k)
- if stored and isinstance(v, session.OpenERPSession):
- v.contexts_store.update(stored.contexts_store)
- v.domains_store.update(stored.domains_store)
- if not hasattr(v, 'jsonp_requests'):
- v.jsonp_requests = {}
- v.jsonp_requests.update(getattr(
- stored, 'jsonp_requests', {}))
-
- # add missing keys
- for k, v in in_store.iteritems():
- if k not in request.session and k not in removed_sessions:
- request.session[k] = v
-
- session_store.save(request.session)
-
-#----------------------------------------------------------
-# OpenERP Web WSGI Application
-#----------------------------------------------------------
-# Add potentially missing (older ubuntu) font mime types
-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
- def __call__(self, environ, start_response):
- def start_wrapped(status, headers):
- referer = environ.get('HTTP_REFERER', '')
- parsed = urlparse.urlparse(referer)
- debug = parsed.query.count('debug') >= 1
-
- new_headers = []
- unwanted_keys = ['Last-Modified']
- if debug:
- new_headers = [('Cache-Control', 'no-cache')]
- unwanted_keys += ['Expires', 'Etag', 'Cache-Control']
-
- for k, v in headers:
- if k not in unwanted_keys:
- new_headers.append((k, v))
-
- start_response(status, new_headers)
- return self.app(environ, start_wrapped)
-
-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)
-
- 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)
-
- if options.session_storage:
- if not os.path.exists(options.session_storage):
- os.mkdir(options.session_storage, 0700)
- self.session_storage = options.session_storage
- _logger.debug('HTTP sessions stored in: %s', self.session_storage)
-
- def __call__(self, environ, start_response):
- """ Handle a WSGI request
- """
- return self.dispatch(environ, start_response)
-
- def dispatch(self, environ, start_response):
- """
- Performs the actual WSGI dispatching for the application, may be
- wrapped during the initialization of the object.
-
- Call the object directly.
- """
- request = werkzeug.wrappers.Request(environ)
- request.parameter_storage_class = werkzeug.datastructures.ImmutableDict
- request.app = self
-
- handler = self.find_handler(*(request.path.split('/')[1:]))
-
- if not handler:
- response = werkzeug.exceptions.NotFound()
- else:
- with session_context(request, self.session_storage, self.httpsession_cookie) as session:
- result = handler( request, self.config)
-
- if isinstance(result, basestring):
- headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))]
- response = werkzeug.wrappers.Response(result, headers=headers)
- else:
- response = result
-
- if hasattr(response, 'set_cookie'):
- response.set_cookie(self.httpsession_cookie, session.sid)
-
- return response(environ, start_response)
-
- def _load_addons(self):
- """
- Loads all addons at the specified addons path, returns a mapping of
- static URLs to the corresponding directories
- """
- statics = {}
- for addons_path in self.config.addons_path:
- for module in os.listdir(addons_path):
- if module not in addons_module:
- manifest_path = os.path.join(addons_path, module, '__openerp__.py')
- path_static = os.path.join(addons_path, module, 'static')
- if os.path.isfile(manifest_path) and os.path.isdir(path_static):
- manifest = ast.literal_eval(open(manifest_path).read())
- manifest['addons_path'] = addons_path
- _logger.debug("Loading %s", module)
- if 'openerp.addons' in sys.modules:
- m = __import__('openerp.addons.' + module)
- else:
- m = __import__(module)
- addons_module[module] = m
- addons_manifest[module] = manifest
- statics['/%s/static' % module] = path_static
- for k, v in controllers_class:
- if k not in controllers_object:
- o = v()
- controllers_object[k] = o
- if hasattr(o, '_cp_path'):
- controllers_path[o._cp_path] = o
- return statics
-
- def find_handler(self, *l):
- """
- Tries to discover the controller handling the request for the path
- specified by the provided parameters
-
- :param l: path sections to a controller or controller method
- :returns: a callable matching the path sections, or ``None``
- :rtype: ``Controller | None``
- """
- if l:
- ps = '/' + '/'.join(l)
- meth = 'index'
- while ps:
- c = controllers_path.get(ps)
- if c:
- m = getattr(c, meth, None)
- if m and getattr(m, 'exposed', False):
- _logger.debug("Dispatching to %s %s %s", ps, c, meth)
- return m
- ps, _slash, meth = ps.rpartition('/')
- if not ps and meth:
- ps = '/'
- return None
-
-# vim:et:ts=4:sw=4:
diff --git a/addons/web/common/nonliterals.py b/addons/web/common/nonliterals.py
deleted file mode 100644
index 4ee6d122f44..00000000000
--- a/addons/web/common/nonliterals.py
+++ /dev/null
@@ -1,267 +0,0 @@
-# -*- coding: utf-8 -*-
-""" Manages the storage and lifecycle of non-literal domains and contexts
-(and potentially other structures) which have to be evaluated with client data,
-but still need to be safely round-tripped to and from the browser (and thus
-can't be sent there themselves).
-"""
-import binascii
-import hashlib
-import simplejson.encoder
-
-__all__ = ['Domain', 'Context', 'NonLiteralEncoder', 'non_literal_decoder', 'CompoundDomain', 'CompoundContext']
-
-#: 48 bits should be sufficient to have almost no chance of collision
-#: with a million hashes, according to hg@67081329d49a
-SHORT_HASH_BYTES_SIZE = 6
-
-class NonLiteralEncoder(simplejson.encoder.JSONEncoder):
- def default(self, object):
- if not isinstance(object, (BaseDomain, BaseContext)):
- return super(NonLiteralEncoder, self).default(object)
- if isinstance(object, Domain):
- return {
- '__ref': 'domain',
- '__id': object.key,
- '__debug': object.get_domain_string()
- }
- elif isinstance(object, Context):
- return {
- '__ref': 'context',
- '__id': object.key,
- '__debug': object.get_context_string()
- }
- elif isinstance(object, CompoundDomain):
- return {
- '__ref': 'compound_domain',
- '__domains': object.domains,
- '__eval_context': object.get_eval_context()
- }
- elif isinstance(object, CompoundContext):
- return {
- '__ref': 'compound_context',
- '__contexts': object.contexts,
- '__eval_context': object.get_eval_context()
- }
- raise TypeError('Could not encode unknown non-literal %s' % object)
-
-_ALLOWED_KEYS = frozenset(['__ref', "__id", '__domains', '__debug',
- '__contexts', '__eval_context'])
-
-def non_literal_decoder(dct):
- """ Decodes JSON dicts into :class:`Domain` and :class:`Context` based on
- magic attribute tags.
- """
- if '__ref' in dct:
- for x in dct:
- if x not in _ALLOWED_KEYS:
- raise ValueError("'%s' key not allowed in non literal domain/context" % x)
- if dct['__ref'] == 'domain':
- return Domain(None, key=dct['__id'])
- elif dct['__ref'] == 'context':
- return Context(None, key=dct['__id'])
- elif dct["__ref"] == "compound_domain":
- cdomain = CompoundDomain()
- for el in dct["__domains"]:
- cdomain.domains.append(el)
- cdomain.set_eval_context(dct.get("__eval_context"))
- return cdomain
- elif dct["__ref"] == "compound_context":
- ccontext = CompoundContext()
- for el in dct["__contexts"]:
- ccontext.contexts.append(el)
- ccontext.set_eval_context(dct.get("__eval_context"))
- return ccontext
- return dct
-
-# TODO: use abstract base classes if 2.6+?
-class BaseDomain(object):
- def evaluate(self, context=None):
- raise NotImplementedError('Non literals must implement evaluate()')
-
-class BaseContext(object):
- def evaluate(self, context=None):
- raise NotImplementedError('Non literals must implement evaluate()')
-
-class Domain(BaseDomain):
- def __init__(self, session, domain_string=None, key=None):
- """ Uses session information to store the domain string and map it to a
- domain key, which can be safely round-tripped to the client.
-
- If initialized with a domain string, will generate a key for that
- string and store the domain string out of the way. When initialized
- with a key, considers this key is a reference to an existing domain
- string.
-
- :param session: the OpenERP Session to use when evaluating the domain
- :type session: web.common.session.OpenERPSession
- :param str domain_string: a non-literal domain in string form
- :param str key: key used to retrieve the domain string
- """
- if domain_string and key:
- raise ValueError("A nonliteral domain can not take both a key "
- "and a domain string")
-
- self.session = session
- if domain_string:
- self.key = binascii.hexlify(
- hashlib.sha256(domain_string).digest()[:SHORT_HASH_BYTES_SIZE])
- self.session.domains_store[self.key] = domain_string
- elif key:
- self.key = key
-
- def get_domain_string(self):
- """ Retrieves the domain string linked to this non-literal domain in
- the provided session.
- """
- return self.session.domains_store[self.key]
-
- def evaluate(self, context=None):
- """ Forces the evaluation of the linked domain, using the provided
- context (as well as the session's base context), and returns the
- evaluated result.
- """
- ctx = self.session.evaluation_context(context)
-
- try:
- return eval(self.get_domain_string(), SuperDict(ctx))
- except NameError as e:
- raise ValueError('Error during evaluation of this domain: "%s", message: "%s"' % (self.get_domain_string(), e.message))
-
-class Context(BaseContext):
- def __init__(self, session, context_string=None, key=None):
- """ Uses session information to store the context string and map it to
- a key (stored in a secret location under a secret mountain), which can
- be safely round-tripped to the client.
-
- If initialized with a context string, will generate a key for that
- string and store the context string out of the way. When initialized
- with a key, considers this key is a reference to an existing context
- string.
-
- :param session: the OpenERP Session to use when evaluating the context
- :type session: web.common.session.OpenERPSession
- :param str context_string: a non-literal context in string form
- :param str key: key used to retrieve the context string
- """
- if context_string and key:
- raise ValueError("A nonliteral domain can not take both a key "
- "and a domain string")
-
- self.session = session
-
- if context_string:
- self.key = binascii.hexlify(
- hashlib.sha256(context_string).digest()[:SHORT_HASH_BYTES_SIZE])
- self.session.contexts_store[self.key] = context_string
- elif key:
- self.key = key
-
- def get_context_string(self):
- """ Retrieves the context string linked to this non-literal context in
- the provided session.
- """
- return self.session.contexts_store[self.key]
-
- def evaluate(self, context=None):
- """ Forces the evaluation of the linked context, using the provided
- context (as well as the session's base context), and returns the
- evaluated result.
- """
- ctx = self.session.evaluation_context(context)
-
- try:
- return eval(self.get_context_string(), SuperDict(ctx))
- except NameError as e:
- raise ValueError('Error during evaluation of this context: "%s", message: "%s"' % (self.get_context_string(), e.message))
-
-class SuperDict(dict):
- def __getattr__(self, name):
- try:
- return self[name]
- except KeyError:
- raise AttributeError(name)
- def __getitem__(self, key):
- tmp = super(SuperDict, self).__getitem__(key)
- if isinstance(tmp, dict):
- return SuperDict(tmp)
- return tmp
-
-class CompoundDomain(BaseDomain):
- def __init__(self, *domains):
- self.domains = []
- self.session = None
- self.eval_context = None
- for domain in domains:
- self.add(domain)
-
- def evaluate(self, context=None):
- ctx = dict(context or {})
- eval_context = self.get_eval_context()
- if eval_context:
- eval_context = self.session.eval_context(eval_context)
- ctx.update(eval_context)
- final_domain = []
- for domain in self.domains:
- if not isinstance(domain, (list, BaseDomain)):
- raise TypeError(
- "Domain %r is not a list or a nonliteral Domain" % domain)
-
- if isinstance(domain, list):
- final_domain.extend(domain)
- continue
-
- domain.session = self.session
- final_domain.extend(domain.evaluate(ctx))
- return final_domain
-
- def add(self, domain):
- self.domains.append(domain)
- return self
-
- def set_eval_context(self, eval_context):
- self.eval_context = eval_context
- return self
-
- def get_eval_context(self):
- return self.eval_context
-
-class CompoundContext(BaseContext):
- def __init__(self, *contexts):
- self.contexts = []
- self.eval_context = None
- self.session = None
- for context in contexts:
- self.add(context)
-
- def evaluate(self, context=None):
- ctx = dict(context or {})
- eval_context = self.get_eval_context()
- if eval_context:
- eval_context = self.session.eval_context(eval_context)
- ctx.update(eval_context)
- final_context = {}
- for context_to_eval in self.contexts:
- if not isinstance(context_to_eval, (dict, BaseContext)):
- raise TypeError(
- "Context %r is not a dict or a nonliteral Context" % context_to_eval)
-
- if isinstance(context_to_eval, dict):
- final_context.update(context_to_eval)
- continue
-
- ctx.update(final_context)
-
- context_to_eval.session = self.session
- final_context.update(context_to_eval.evaluate(ctx))
- return final_context
-
- def add(self, context):
- self.contexts.append(context)
- return self
-
- def set_eval_context(self, eval_context):
- self.eval_context = eval_context
- return self
-
- def get_eval_context(self):
- return self.eval_context
diff --git a/addons/web/common/openerplib/__init__.py b/addons/web/common/openerplib/__init__.py
deleted file mode 100644
index 44701ec22fe..00000000000
--- a/addons/web/common/openerplib/__init__.py
+++ /dev/null
@@ -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 *
-
diff --git a/addons/web/common/openerplib/dates.py b/addons/web/common/openerplib/dates.py
deleted file mode 100644
index 6d4fa9e2f63..00000000000
--- a/addons/web/common/openerplib/dates.py
+++ /dev/null
@@ -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)
-
diff --git a/addons/web/common/openerplib/main.py b/addons/web/common/openerplib/main.py
deleted file mode 100644
index 93c2d1da69d..00000000000
--- a/addons/web/common/openerplib/main.py
+++ /dev/null
@@ -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)
-
diff --git a/addons/web/common/release.py b/addons/web/common/release.py
deleted file mode 100644
index b9dafd330d0..00000000000
--- a/addons/web/common/release.py
+++ /dev/null
@@ -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"
diff --git a/addons/web/common/session.py b/addons/web/common/session.py
deleted file mode 100644
index 45bbb32f64c..00000000000
--- a/addons/web/common/session.py
+++ /dev/null
@@ -1,270 +0,0 @@
-#!/usr/bin/python
-import datetime
-import babel
-import dateutil.relativedelta
-import logging
-import time
-import sys
-
-import openerplib
-
-from . 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 OpenERPSession(object):
- """
- An OpenERP RPC session, a given user can own multiple such sessions
- in a web session.
-
- .. attribute:: context
-
- The session context, a ``dict``. Can be reloaded by calling
- :meth:`openerpweb.openerpweb.OpenERPSession.get_context`
-
- .. attribute:: domains_store
-
- A ``dict`` matching domain keys to evaluable (but non-literal) domains.
-
- Used to store references to non-literal domains which need to be
- round-tripped to the client browser.
- """
- def __init__(self):
- self._creation_time = time.time()
- self.config = None
- self._db = False
- self._uid = False
- self._login = False
- self._password = False
- self._suicide = False
- self.context = {}
- self.contexts_store = {}
- 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 proxy(self, service):
- return self.build_connection().get_service(service)
-
- def bind(self, db, uid, login, password):
- self._db = db
- self._uid = uid
- self._login = login
- 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)
-
- if uid: self.get_context()
- return uid
-
- def assert_valid(self, force=False):
- """
- Ensures this session is valid (logged into the openerp server)
- """
- self.build_connection().check_login(force)
-
- def ensure_valid(self):
- if self._uid:
- try:
- self.assert_valid(True)
- except Exception:
- self._uid = None
-
- def execute(self, model, func, *l, **d):
- self.assert_valid()
- model = self.build_connection().get_model(model)
- r = getattr(model, func)(*l, **d)
- return r
-
- def exec_workflow(self, model, id, signal):
- self.assert_valid()
- r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
- return r
-
- def model(self, model):
- """ Get an RPC proxy for the object ``model``, bound to this session.
-
- :param model: an OpenERP model name
- :type model: str
- :rtype: a model object
- """
- return self.build_connection().get_model(model)
-
- def get_context(self):
- """ Re-initializes the current user's session context (based on
- his preferences) by calling res.users.get_context() with the old
- context
-
- :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['uid'] = self._uid
- self._fix_lang(self.context)
- return self.context
-
- def _fix_lang(self, context):
- """ OpenERP provides languages which may not make sense and/or may not
- be understood by the web client's libraries.
-
- Fix those here.
-
- :param dict context: context to fix
- """
- lang = context['lang']
-
- # inane OpenERP locale
- if lang == 'ar_AR':
- lang = 'ar'
-
- # lang to lang_REGION (datejs only handles lang_REGION, no bare langs)
- if lang in babel.core.LOCALE_ALIASES:
- lang = babel.core.LOCALE_ALIASES[lang]
-
- context['lang'] = lang
-
- @property
- def base_eval_context(self):
- """ Default evaluation context for the session.
-
- Used to evaluate contexts and domains.
- """
- base = dict(
- uid=self._uid,
- current_date=datetime.date.today().strftime('%Y-%m-%d'),
- time=time,
- datetime=datetime,
- relativedelta=dateutil.relativedelta.relativedelta
- )
- base.update(self.context)
- return base
-
- def evaluation_context(self, context=None):
- """ Returns the session's evaluation context, augmented with the
- provided context if any.
-
- :param dict context: to add merge in the session's base eval context
- :returns: the augmented context
- :rtype: dict
- """
- d = dict(self.base_eval_context)
- if context:
- d.update(context)
- d['context'] = d
- return d
-
- def eval_context(self, context_to_eval, context=None):
- """ Evaluates the provided context_to_eval in the context (haha) of
- the context. Also merges the evaluated context with the session's context.
-
- :param context_to_eval: a context to evaluate. Must be a dict or a
- non-literal context. If it's a dict, will be
- returned as-is
- :type context_to_eval: openerpweb.nonliterals.Context
- :returns: the evaluated context
- :rtype: dict
-
- :raises: ``TypeError`` if ``context_to_eval`` is neither a dict nor
- a Context
- """
- ctx = dict(
- self.base_eval_context,
- **(context or {}))
-
- # adding the context of the session to send to the openerp server
- ccontext = nonliterals.CompoundContext(self.context, context_to_eval or {})
- ccontext.session = self
- return ccontext.evaluate(ctx)
-
- def eval_domain(self, domain, context=None):
- """ Evaluates the provided domain using the provided context
- (merged with the session's evaluation context)
-
- :param domain: an OpenERP domain as a list or as a
- :class:`openerpweb.nonliterals.Domain` instance
-
- In the second case, it will be evaluated and returned.
- :type domain: openerpweb.nonliterals.Domain
- :param dict context: the context to use in the evaluation, if any.
- :returns: the evaluated domain
- :rtype: list
-
- :raises: ``TypeError`` if ``domain`` is neither a list nor a Domain
- """
- if isinstance(domain, list):
- return domain
-
- cdomain = nonliterals.CompoundDomain(domain)
- cdomain.session = self
- return cdomain.evaluate(context or {})
-
-# vim:et:ts=4:sw=4:
diff --git a/addons/web/common/xml2json.py b/addons/web/common/xml2json.py
deleted file mode 100644
index df3aad67fa5..00000000000
--- a/addons/web/common/xml2json.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# xml2json-direct
-# Simple and straightforward XML-to-JSON converter in Python
-# New BSD Licensed
-#
-# URL: http://code.google.com/p/xml2json-direct/
-
-def from_elementtree(el, preserve_whitespaces=False):
- res = {}
- if el.tag[0] == "{":
- ns, name = el.tag.rsplit("}", 1)
- res["tag"] = name
- res["namespace"] = ns[1:]
- else:
- res["tag"] = el.tag
- res["attrs"] = {}
- for k, v in el.items():
- res["attrs"][k] = v
- kids = []
- if el.text and (preserve_whitespaces or el.text.strip() != ''):
- kids.append(el.text)
- for kid in el:
- kids.append(from_elementtree(kid, preserve_whitespaces))
- if kid.tail and (preserve_whitespaces or kid.tail.strip() != ''):
- kids.append(kid.tail)
- res["children"] = kids
- return res