1 # -*- coding: utf-8 -*-
2 #----------------------------------------------------------
3 # OpenERP Web HTTP layer
4 #----------------------------------------------------------
28 import werkzeug.contrib.sessions
29 import werkzeug.datastructures
30 import werkzeug.exceptions
32 import werkzeug.wrappers
34 import werkzeug.routing as routing
39 from openerp.service import security, model as service_model
40 from openerp.tools import config
45 _logger = logging.getLogger(__name__)
47 #----------------------------------------------------------
49 #----------------------------------------------------------
50 class WebRequest(object):
51 """ Parent class for all OpenERP Web request types, mostly deals with
52 initialization and setup of the request object (the dispatching itself has
53 to be handled by the subclasses)
55 :param request: a wrapped werkzeug Request object
56 :type request: :class:`werkzeug.wrappers.BaseRequest`
58 .. attribute:: httprequest
60 the original :class:`werkzeug.wrappers.Request` object provided to the
63 .. attribute:: httpsession
67 Use ``self.session`` instead.
71 :class:`~collections.Mapping` of request parameters, not generally
72 useful as they're provided directly to the handler method as keyword
75 .. attribute:: session_id
77 opaque identifier for the :class:`session.OpenERPSession` instance of
80 .. attribute:: session
82 a :class:`OpenERPSession` holding the HTTP session data for the
85 .. attribute:: context
87 :class:`~collections.Mapping` of context values for the current request
91 ``str``, the name of the database linked to the current request. Can be ``None``
92 if the current request uses the ``none`` authentication.
96 ``int``, the id of the user related to the current request. Can be ``None``
97 if the current request uses the ``none`` authenticatoin.
99 def __init__(self, httprequest):
100 self.httprequest = httprequest
101 self.httpresponse = None
102 self.httpsession = httprequest.session
103 self.session = httprequest.session
104 self.session_id = httprequest.session.sid
105 self.disable_db = False
108 self.auth_method = None
111 self.func_request_type = None
112 # set db/uid trackers - they're cleaned up at the WSGI
113 # dispatching phase in openerp.service.wsgi_server.application
115 threading.current_thread().dbname = self.db
117 threading.current_thread().uid = self.session.uid
118 self.context = dict(self.session.context)
119 self.lang = self.context["lang"]
121 def _authenticate(self):
124 self.session.check_security()
125 except SessionExpiredException, e:
126 self.session.logout()
127 raise SessionExpiredException("Session expired for request %s" % self.httprequest)
128 auth_methods[self.auth_method]()
132 The registry to the database linked to this request. Can be ``None`` if the current request uses the
133 ``none'' authentication.
135 return openerp.modules.registry.RegistryManager.get(self.db) if self.db else None
140 The registry to the database linked to this request. Can be ``None`` if the current request uses the
141 ``none'' authentication.
143 return self.session.db if not self.disable_db else None
148 The cursor initialized for the current method call. If the current request uses the ``none`` authentication
149 trying to access this property will raise an exception.
151 # some magic to lazy create the cr
153 self._cr_cm = self.registry.cursor()
154 self._cr = self._cr_cm.__enter__()
157 def _call_function(self, *args, **kwargs):
160 # ugly syntax only to get the __exit__ arguments to pass to self._cr
162 class with_obj(object):
165 def __exit__(self, *args):
167 request._cr_cm.__exit__(*args)
168 request._cr_cm = None
172 if self.func_request_type != self._request_type:
173 raise Exception("%s, %s: Function declared as capable of handling request of type '%s' but called with a request of type '%s'" \
174 % (self.func, self.httprequest.path, self.func_request_type, self._request_type))
175 return self.func(*args, **kwargs)
177 # just to be sure no one tries to re-use the request
178 self.disable_db = True
183 return 'debug' in self.httprequest.args
185 @contextlib.contextmanager
186 def registry_cr(self):
187 warnings.warn('please use request.registry and request.cr directly', DeprecationWarning)
188 yield (self.registry, self.cr)
190 def auth_method_user():
191 request.uid = request.session.uid
193 raise SessionExpiredException("Session expired")
195 def auth_method_admin():
197 raise SessionExpiredException("No valid database for request %s" % request.httprequest)
198 request.uid = openerp.SUPERUSER_ID
200 def auth_method_none():
201 request.disable_db = True
205 "user": auth_method_user,
206 "admin": auth_method_admin,
207 "none": auth_method_none,
210 def route(route, type="http", auth="user"):
212 Decorator marking the decorated method as being a handler for requests. The method must be part of a subclass
215 :param route: string or array. The route part that will determine which http requests will match the decorated
216 method. Can be a single string or an array of strings. See werkzeug's routing documentation for the format of
217 route expression ( http://werkzeug.pocoo.org/docs/routing/ ).
218 :param type: The type of request, can be ``'http'`` or ``'json'``.
219 :param auth: The type of authentication method, can on of the following:
221 * ``user``: The user must be authenticated and the current request will perform using the rights of the
223 * ``admin``: The user may not be authenticated and the current request will perform using the admin user.
224 * ``none``: The method is always active, even if there is no database. Mainly used by the framework and
225 authentication modules. There request code will not have any facilities to access the database nor have any
226 configuration indicating the current database nor the current user.
228 assert type in ["http", "json"]
229 assert auth in auth_methods.keys()
231 if isinstance(route, list):
236 if getattr(f, "auth", None) is None:
241 def reject_nonliteral(dct):
244 "Non literal contexts can not be sent to the server anymore (%r)" % (dct,))
247 class JsonRequest(WebRequest):
248 """ JSON-RPC2 over HTTP.
252 --> {"jsonrpc": "2.0",
254 "params": {"context": {},
258 <-- {"jsonrpc": "2.0",
259 "result": { "res1": "val1" },
262 Request producing a error::
264 --> {"jsonrpc": "2.0",
266 "params": {"context": {},
270 <-- {"jsonrpc": "2.0",
272 "message": "End user error message.",
273 "data": {"code": "codestring",
274 "debug": "traceback" } },
278 _request_type = "json"
280 def __init__(self, *args):
281 super(JsonRequest, self).__init__(*args)
283 self.jsonp_handler = None
285 args = self.httprequest.args
286 jsonp = args.get('jsonp')
289 request_id = args.get('id')
291 if jsonp and self.httprequest.method == 'POST':
292 # jsonp 2 steps step1 POST: save call
294 self.session.jsonp_requests[request_id] = self.httprequest.form['r']
295 self.session.modified = True
296 headers=[('Content-Type', 'text/plain; charset=utf-8')]
297 r = werkzeug.wrappers.Response(request_id, headers=headers)
299 self.jsonp_handler = handler
301 elif jsonp and args.get('r'):
303 request = args.get('r')
304 elif jsonp and request_id:
305 # jsonp 2 steps step2 GET: run and return result
306 request = self.session.jsonp_requests.pop(request_id, "")
309 request = self.httprequest.stream.read()
311 # Read POST content or POST Form Data named "request"
312 self.jsonrequest = simplejson.loads(request, object_hook=reject_nonliteral)
313 self.params = dict(self.jsonrequest.get("params", {}))
314 self.context = self.params.pop('context', self.session.context)
317 """ Calls the method asked for by the JSON-RPC2 or JSONP request
319 if self.jsonp_handler:
320 return self.jsonp_handler()
321 response = {"jsonrpc": "2.0" }
325 response['id'] = self.jsonrequest.get('id')
326 response["result"] = self._call_function(**self.params)
327 except AuthenticationError, e:
328 _logger.exception("Exception during JSON request handling.")
329 se = serialize_exception(e)
332 'message': "OpenERP Session Invalid",
336 _logger.exception("Exception during JSON request handling.")
337 se = serialize_exception(e)
340 'message': "OpenERP Server Error",
344 response["error"] = error
347 # If we use jsonp, that's mean we are called from another host
348 # Some browser (IE and Safari) do no allow third party cookies
349 # We need then to manage http sessions manually.
350 response['session_id'] = self.session_id
351 mime = 'application/javascript'
352 body = "%s(%s);" % (self.jsonp, simplejson.dumps(response),)
354 mime = 'application/json'
355 body = simplejson.dumps(response)
357 r = werkzeug.wrappers.Response(body, headers=[('Content-Type', mime), ('Content-Length', len(body))])
360 def serialize_exception(e):
362 "name": type(e).__module__ + "." + type(e).__name__ if type(e).__module__ else type(e).__name__,
363 "debug": traceback.format_exc(),
364 "message": u"%s" % e,
365 "arguments": to_jsonable(e.args),
367 if isinstance(e, openerp.osv.osv.except_osv):
368 tmp["exception_type"] = "except_osv"
369 elif isinstance(e, openerp.exceptions.Warning):
370 tmp["exception_type"] = "warning"
371 elif isinstance(e, openerp.exceptions.AccessError):
372 tmp["exception_type"] = "access_error"
373 elif isinstance(e, openerp.exceptions.AccessDenied):
374 tmp["exception_type"] = "access_denied"
378 if isinstance(o, str) or isinstance(o,unicode) or isinstance(o, int) or isinstance(o, long) \
379 or isinstance(o, bool) or o is None or isinstance(o, float):
381 if isinstance(o, list) or isinstance(o, tuple):
382 return [to_jsonable(x) for x in o]
383 if isinstance(o, dict):
385 for k, v in o.items():
386 tmp[u"%s" % k] = to_jsonable(v)
394 Use the ``route()`` decorator instead.
397 base = f.__name__.lstrip('/')
398 if f.__name__ == "index":
400 return route([base, base + "/<path:_ignored_path>"], type="json", auth="user")(f)
402 class HttpRequest(WebRequest):
403 """ Regular GET/POST request
405 _request_type = "http"
407 def __init__(self, *args):
408 super(HttpRequest, self).__init__(*args)
409 params = dict(self.httprequest.args)
410 params.update(self.httprequest.form)
411 params.update(self.httprequest.files)
412 params.pop('session_id', None)
417 r = self._call_function(**self.params)
418 except werkzeug.exceptions.HTTPException, e:
421 _logger.exception("An exception occured during an http request")
422 se = serialize_exception(e)
425 'message': "OpenERP Server Error",
428 r = werkzeug.exceptions.InternalServerError(cgi.escape(simplejson.dumps(error)))
431 r = werkzeug.wrappers.Response(status=204) # no content
434 def make_response(self, data, headers=None, cookies=None):
435 """ Helper for non-HTML responses, or HTML responses with custom
436 response headers or cookies.
438 While handlers can just return the HTML markup of a page they want to
439 send as a string if non-HTML data is returned they need to create a
440 complete response object, or the returned data will not be correctly
441 interpreted by the clients.
443 :param basestring data: response body
444 :param headers: HTTP headers to set on the response
445 :type headers: ``[(name, value)]``
446 :param collections.Mapping cookies: cookies to set on the client
448 response = werkzeug.wrappers.Response(data, headers=headers)
450 for k, v in cookies.iteritems():
451 response.set_cookie(k, v)
454 def not_found(self, description=None):
455 """ Helper for 404 response, return its result from the method
457 return werkzeug.exceptions.NotFound(description)
463 Use the ``route()`` decorator instead.
466 base = f.__name__.lstrip('/')
467 if f.__name__ == "index":
469 return route([base, base + "/<path:_ignored_path>"], type="http", auth="user")(f)
471 #----------------------------------------------------------
472 # Local storage of requests
473 #----------------------------------------------------------
474 from werkzeug.local import LocalStack
476 _request_stack = LocalStack()
479 @contextlib.contextmanager
480 def set_request(req):
481 _request_stack.push(req)
488 request = _request_stack()
490 A global proxy that always redirect to the current request object.
493 #----------------------------------------------------------
494 # Controller registration with a metaclass
495 #----------------------------------------------------------
498 controllers_per_module = {}
500 class ControllerType(type):
501 def __init__(cls, name, bases, attrs):
502 super(ControllerType, cls).__init__(name, bases, attrs)
504 # flag old-style methods with req as first argument
505 for k, v in attrs.items():
506 if inspect.isfunction(v):
507 spec = inspect.getargspec(v)
508 first_arg = spec.args[1] if len(spec.args) >= 2 else None
509 if first_arg in ["req", "request"]:
510 v._first_arg_is_req = True
512 # store the controller in the controllers list
513 name_class = ("%s.%s" % (cls.__module__, cls.__name__), cls)
514 class_path = name_class[0].split(".")
515 if not class_path[:2] == ["openerp", "addons"]:
518 # we want to know all modules that have controllers
519 module = class_path[2]
520 # but we only store controllers directly inheriting from Controller
521 if not "Controller" in globals() or not Controller in bases:
523 controllers_per_module.setdefault(module, []).append(name_class)
525 class Controller(object):
526 __metaclass__ = ControllerType
528 #############################
530 #############################
532 class AuthenticationError(Exception):
535 class SessionExpiredException(Exception):
538 class Service(object):
541 Use ``openerp.netsvc.dispatch_rpc()`` instead.
543 def __init__(self, session, service_name):
544 self.session = session
545 self.service_name = service_name
547 def __getattr__(self, method):
548 def proxy_method(*args):
549 result = openerp.netsvc.dispatch_rpc(self.service_name, method, args)
556 Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
558 def __init__(self, session, model):
559 self.session = session
561 self.proxy = self.session.proxy('object')
563 def __getattr__(self, method):
564 self.session.assert_valid()
565 def proxy(*args, **kw):
566 # Can't provide any retro-compatibility for this case, so we check it and raise an Exception
567 # to tell the programmer to adapt his code
568 if not request.db or not request.uid or self.session.db != request.db \
569 or self.session.uid != request.uid:
570 raise Exception("Trying to use Model with badly configured database or user.")
572 mod = request.registry.get(self.model)
573 if method.startswith('_'):
574 raise Exception("Access denied")
575 meth = getattr(mod, method)
577 result = meth(cr, request.uid, *args, **kw)
580 if isinstance(result, list) and len(result) > 0 and "id" in result[0]:
584 result = [index[x] for x in args[0] if x in index]
588 class OpenERPSession(werkzeug.contrib.sessions.Session):
589 def __init__(self, *args, **kwargs):
591 self.modified = False
592 super(OpenERPSession, self).__init__(*args, **kwargs)
594 self._default_values()
595 self.modified = False
597 def __getattr__(self, attr):
598 return self.get(attr, None)
599 def __setattr__(self, k, v):
600 if getattr(self, "inited", False):
602 object.__getattribute__(self, k)
604 return self.__setitem__(k, v)
605 object.__setattr__(self, k, v)
607 def authenticate(self, db, login=None, password=None, uid=None):
609 Authenticate the current user with the given db, login and password. If successful, store
610 the authentication parameters in the current session and request.
612 :param uid: If not None, that user id will be used instead the login to authenticate the user.
616 wsgienv = request.httprequest.environ
618 base_location=request.httprequest.url_root.rstrip('/'),
619 HTTP_HOST=wsgienv['HTTP_HOST'],
620 REMOTE_ADDR=wsgienv['REMOTE_ADDR'],
622 uid = openerp.netsvc.dispatch_rpc('common', 'authenticate', [db, login, password, env])
624 security.check(db, uid, password)
628 self.password = password
630 request.disable_db = False
632 if uid: self.get_context()
635 def check_security(self):
637 Chech the current authentication parameters to know if those are still valid. This method
638 should be called at each request. If the authentication fails, a ``SessionExpiredException``
641 if not self.db or not self.uid:
642 raise SessionExpiredException("Session expired")
643 security.check(self.db, self.uid, self.password)
646 for k in self.keys():
648 self._default_values()
650 def _default_values(self):
651 self.setdefault("db", None)
652 self.setdefault("uid", None)
653 self.setdefault("login", None)
654 self.setdefault("password", None)
655 self.setdefault("context", {'tz': "UTC", "uid": None})
656 self.setdefault("jsonp_requests", {})
658 def get_context(self):
660 Re-initializes the current user's session context (based on
661 his preferences) by calling res.users.get_context() with the old
664 :returns: the new context
666 assert self.uid, "The user needs to be logged-in to initialize his context"
667 self.context = request.registry.get('res.users').context_get(request.cr, request.uid) or {}
668 self.context['uid'] = self.uid
669 self._fix_lang(self.context)
672 def _fix_lang(self, context):
673 """ OpenERP provides languages which may not make sense and/or may not
674 be understood by the web client's libraries.
678 :param dict context: context to fix
680 lang = context['lang']
682 # inane OpenERP locale
686 # lang to lang_REGION (datejs only handles lang_REGION, no bare langs)
687 if lang in babel.core.LOCALE_ALIASES:
688 lang = babel.core.LOCALE_ALIASES[lang]
690 context['lang'] = lang or 'en_US'
693 Damn properties for retro-compatibility. All of that is deprecated, all
700 def _db(self, value):
706 def _uid(self, value):
712 def _login(self, value):
718 def _password(self, value):
719 self.password = value
721 def send(self, service_name, method, *args):
724 Use ``openerp.netsvc.dispatch_rpc()`` instead.
726 return openerp.netsvc.dispatch_rpc(service_name, method, args)
728 def proxy(self, service):
731 Use ``openerp.netsvc.dispatch_rpc()`` instead.
733 return Service(self, service)
735 def assert_valid(self, force=False):
738 Use ``check_security()`` instead.
740 Ensures this session is valid (logged into the openerp server)
742 if self.uid and not force:
744 # TODO use authenticate instead of login
745 self.uid = self.proxy("common").login(self.db, self.login, self.password)
747 raise AuthenticationError("Authentication failure")
749 def ensure_valid(self):
752 Use ``check_security()`` instead.
756 self.assert_valid(True)
760 def execute(self, model, func, *l, **d):
763 Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
765 model = self.model(model)
766 r = getattr(model, func)(*l, **d)
769 def exec_workflow(self, model, id, signal):
772 Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
775 r = self.proxy('object').exec_workflow(self.db, self.uid, self.password, model, signal, id)
778 def model(self, model):
781 Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
783 Get an RPC proxy for the object ``model``, bound to this session.
785 :param model: an OpenERP model name
787 :rtype: a model object
790 raise SessionExpiredException("Session expired")
792 return Model(self, model)
794 def session_gc(session_store):
795 if random.random() < 0.001:
796 # we keep session one week
797 last_week = time.time() - 60*60*24*7
798 for fname in os.listdir(session_store.path):
799 path = os.path.join(session_store.path, fname)
801 if os.path.getmtime(path) < last_week:
806 #----------------------------------------------------------
808 #----------------------------------------------------------
809 # Add potentially missing (older ubuntu) font mime types
810 mimetypes.add_type('application/font-woff', '.woff')
811 mimetypes.add_type('application/vnd.ms-fontobject', '.eot')
812 mimetypes.add_type('application/x-font-ttf', '.ttf')
814 class DisableCacheMiddleware(object):
815 def __init__(self, app):
817 def __call__(self, environ, start_response):
818 def start_wrapped(status, headers):
819 referer = environ.get('HTTP_REFERER', '')
820 parsed = urlparse.urlparse(referer)
821 debug = parsed.query.count('debug') >= 1
824 unwanted_keys = ['Last-Modified']
826 new_headers = [('Cache-Control', 'no-cache')]
827 unwanted_keys += ['Expires', 'Etag', 'Cache-Control']
830 if k not in unwanted_keys:
831 new_headers.append((k, v))
833 start_response(status, new_headers)
834 return self.app(environ, start_wrapped)
839 username = pwd.getpwuid(os.geteuid()).pw_name
842 username = getpass.getuser()
845 path = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
848 except OSError as exc:
849 if exc.errno == errno.EEXIST:
850 # directory exists: ensure it has the correct permissions
851 # this will fail if the directory is not owned by the current user
858 """Root WSGI application for the OpenERP Web Client.
864 self.no_db_router = None
868 # Setup http sessions
869 path = session_path()
870 self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)
871 _logger.debug('HTTP sessions stored in: %s', path)
874 def __call__(self, environ, start_response):
875 """ Handle a WSGI request
877 return self.dispatch(environ, start_response)
879 def dispatch(self, environ, start_response):
881 Performs the actual WSGI dispatching for the application.
884 httprequest = werkzeug.wrappers.Request(environ)
885 httprequest.parameter_storage_class = werkzeug.datastructures.ImmutableDict
886 httprequest.app = self
888 session_gc(self.session_store)
890 sid = httprequest.args.get('session_id')
891 explicit_session = True
893 sid = httprequest.headers.get("X-Openerp-Session-Id")
895 sid = httprequest.cookies.get('session_id')
896 explicit_session = False
898 httprequest.session = self.session_store.new()
900 httprequest.session = self.session_store.get(sid)
902 self._find_db(httprequest)
904 if not "lang" in httprequest.session.context:
905 lang = httprequest.accept_languages.best or "en_US"
906 lang = babel.core.LOCALE_ALIASES.get(lang, lang).replace('-', '_')
907 httprequest.session.context["lang"] = lang
909 request = self._build_request(httprequest)
913 openerp.modules.registry.RegistryManager.check_registry_signaling(db)
915 with set_request(request):
917 result = request.dispatch()
920 openerp.modules.registry.RegistryManager.signal_caches_change(db)
922 if isinstance(result, basestring):
923 headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))]
924 response = werkzeug.wrappers.Response(result, headers=headers)
928 if httprequest.session.should_save:
929 self.session_store.save(httprequest.session)
930 if not explicit_session and hasattr(response, 'set_cookie'):
931 response.set_cookie('session_id', httprequest.session.sid, max_age=90 * 24 * 60 * 60)
933 return response(environ, start_response)
934 except werkzeug.exceptions.HTTPException, e:
935 return e(environ, start_response)
937 def _find_db(self, httprequest):
938 db = db_monodb(httprequest)
939 if db != httprequest.session.db:
940 httprequest.session.logout()
941 httprequest.session.db = db
943 def _build_request(self, httprequest):
944 if httprequest.args.get('jsonp'):
945 return JsonRequest(httprequest)
947 if httprequest.mimetype == "application/json":
948 return JsonRequest(httprequest)
950 return HttpRequest(httprequest)
952 def load_addons(self):
953 """ Load all addons from addons patch containg static files and
954 controllers and configure them. """
956 for addons_path in openerp.modules.module.ad_paths:
957 for module in sorted(os.listdir(str(addons_path))):
958 if module not in addons_module:
959 manifest_path = os.path.join(addons_path, module, '__openerp__.py')
960 path_static = os.path.join(addons_path, module, 'static')
961 if os.path.isfile(manifest_path) and os.path.isdir(path_static):
962 manifest = ast.literal_eval(open(manifest_path).read())
963 manifest['addons_path'] = addons_path
964 _logger.debug("Loading %s", module)
965 if 'openerp.addons' in sys.modules:
966 m = __import__('openerp.addons.' + module)
968 m = __import__(module)
969 addons_module[module] = m
970 addons_manifest[module] = manifest
971 self.statics['/%s/static' % module] = path_static
973 app = werkzeug.wsgi.SharedDataMiddleware(self.dispatch, self.statics)
974 self.dispatch = DisableCacheMiddleware(app)
976 def _build_router(self, db):
977 _logger.info("Generating routing configuration for database %s" % db)
978 routing_map = routing.Map(strict_slashes=False)
980 def gen(modules, nodb_only):
981 for module in modules:
982 for v in controllers_per_module[module]:
985 subclasses = cls.__subclasses__()
986 subclasses = [c for c in subclasses if c.__module__.startswith('openerp.addons.') and
987 c.__module__.split(".")[2] in modules]
989 name = "%s (extended by %s)" % (cls.__name__, ', '.join(sub.__name__ for sub in subclasses))
990 cls = type(name, tuple(reversed(subclasses)), {})
993 members = inspect.getmembers(o)
994 for mk, mv in members:
995 if inspect.ismethod(mv) and getattr(mv, 'exposed', False) and \
996 nodb_only == (getattr(mv, "auth", "none") == "none"):
997 for url in mv.routes:
998 if getattr(mv, "combine", False):
999 url = o._cp_path.rstrip('/') + '/' + url.lstrip('/')
1000 if url.endswith("/") and len(url) > 1:
1002 routing_map.add(routing.Rule(url, endpoint=mv))
1004 modules_set = set(controllers_per_module.keys()) - set(['', 'web'])
1005 # building all none methods
1006 gen(['', "web"] + sorted(modules_set), True)
1010 registry = openerp.modules.registry.RegistryManager.get(db)
1011 with registry.cursor() as cr:
1012 m = registry.get('ir.module.module')
1013 ids = m.search(cr, openerp.SUPERUSER_ID, [('state', '=', 'installed'), ('name', '!=', 'web')])
1014 installed = set(x['name'] for x in m.read(cr, 1, ids, ['name']))
1015 modules_set = modules_set & installed
1017 # building all other methods
1018 gen(['', "web"] + sorted(modules_set), False)
1022 def get_db_router(self, db):
1024 router = self.no_db_router
1026 router = getattr(openerp.modules.registry.RegistryManager.get(db), "werkzeug_http_router", None)
1028 router = self._build_router(db)
1030 self.no_db_router = router
1032 openerp.modules.registry.RegistryManager.get(db).werkzeug_http_router = router
1035 def find_handler(self):
1037 Tries to discover the controller handling the request for the path specified in the request.
1039 path = request.httprequest.path
1040 urls = self.get_db_router(request.db).bind("")
1041 func, arguments = urls.match(path)
1042 arguments = dict([(k, v) for k, v in arguments.items() if not k.startswith("_ignored_")])
1044 @service_model.check
1045 def checked_call(dbname, *a, **kw):
1046 return func(*a, **kw)
1048 def nfunc(*args, **kwargs):
1049 kwargs.update(arguments)
1050 if getattr(func, '_first_arg_is_req', False):
1051 args = (request,) + args
1054 return checked_call(request.db, *args, **kwargs)
1055 return func(*args, **kwargs)
1057 request.func = nfunc
1058 request.auth_method = getattr(func, "auth", "user")
1059 request.func_request_type = func.exposed
1063 def db_list(force=False, httprequest=None):
1064 httprequest = httprequest or request.httprequest
1065 dbs = openerp.netsvc.dispatch_rpc("db", "list", [force])
1066 h = httprequest.environ['HTTP_HOST'].split(':')[0]
1068 r = openerp.tools.config['dbfilter'].replace('%h', h).replace('%d', d)
1069 dbs = [i for i in dbs if re.match(r, i)]
1072 def db_monodb(httprequest=None):
1074 Magic function to find the current database.
1076 Implementation details:
1081 Returns ``None`` if the magic is not magic enough.
1083 httprequest = httprequest or request.httprequest
1087 dbs = db_list(True, httprequest)
1089 # try the db already in the session
1090 db_session = httprequest.session.db
1091 if db_session in dbs:
1094 # if dbfilters was specified when launching the server and there is
1095 # only one possible db, we take that one
1096 if openerp.tools.config['dbfilter'] != ".*" and len(dbs) == 1:
1100 class CommonController(Controller):
1102 @route('/jsonrpc', type='json', auth="none")
1103 def jsonrpc(self, service, method, args):
1104 """ Method used by client APIs to contact OpenERP. """
1105 return openerp.netsvc.dispatch_rpc(service, method, args)
1107 @route('/gen_session_id', type='json', auth="none")
1108 def gen_session_id(self):
1109 nsession = root.session_store.new()
1112 def wsgi_postload():
1115 openerp.wsgi.register_wsgi_handler(root)