diff options
| author | Antony Lesuisse <al@openerp.com> | 2012-10-10 22:44:51 +0200 |
|---|---|---|
| committer | Antony Lesuisse <al@openerp.com> | 2012-10-10 22:44:51 +0200 |
| commit | 07e1fba67d44b7906ff42e5145aff3941e790c99 (patch) | |
| tree | 46fb16d6e87795dc9817af72edbbee4e375748b9 /addons/web/common | |
| parent | ceb6078a7739ab4a6a8c3ded9d5a80e33578fad6 (diff) | |
| parent | ae6ff0764b709880c458c54a850594db8eed795a (diff) | |
[MERGE] remove standalone web client
bzr revid: al@openerp.com-20121010204451-nq3eatsl1x9zi1cf
Diffstat (limited to 'addons/web/common')
| -rw-r--r-- | addons/web/common/__init__.py | 6 | ||||
| -rw-r--r-- | addons/web/common/http.py | 582 | ||||
| -rw-r--r-- | addons/web/common/nonliterals.py | 267 | ||||
| -rw-r--r-- | addons/web/common/openerplib/__init__.py | 32 | ||||
| -rw-r--r-- | addons/web/common/openerplib/dates.py | 97 | ||||
| -rw-r--r-- | addons/web/common/openerplib/main.py | 311 | ||||
| -rw-r--r-- | addons/web/common/release.py | 10 | ||||
| -rw-r--r-- | addons/web/common/session.py | 270 | ||||
| -rw-r--r-- | addons/web/common/xml2json.py | 26 |
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 |
