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 def auth_method_admin():
195 raise SessionExpiredException("No valid database for request %s" % request.httprequest)
196 request.uid = openerp.SUPERUSER_ID
198 def auth_method_none():
199 request.disable_db = True
203 "user": auth_method_user,
204 "admin": auth_method_admin,
205 "none": auth_method_none,
208 def route(route, type="http", auth="user"):
210 Decorator marking the decorated method as being a handler for requests. The method must be part of a subclass
213 :param route: string or array. The route part that will determine which http requests will match the decorated
214 method. Can be a single string or an array of strings. See werkzeug's routing documentation for the format of
215 route expression ( http://werkzeug.pocoo.org/docs/routing/ ).
216 :param type: The type of request, can be ``'http'`` or ``'json'``.
217 :param auth: The type of authentication method, can on of the following:
219 * ``user``: The user must be authenticated and the current request will perform using the rights of the
221 * ``admin``: The user may not be authenticated and the current request will perform using the admin user.
222 * ``none``: The method is always active, even if there is no database. Mainly used by the framework and
223 authentication modules. There request code will not have any facilities to access the database nor have any
224 configuration indicating the current database nor the current user.
226 assert type in ["http", "json"]
227 assert auth in auth_methods.keys()
229 if isinstance(route, list):
234 if getattr(f, "auth", None) is None:
239 def reject_nonliteral(dct):
242 "Non literal contexts can not be sent to the server anymore (%r)" % (dct,))
245 class JsonRequest(WebRequest):
246 """ JSON-RPC2 over HTTP.
250 --> {"jsonrpc": "2.0",
252 "params": {"context": {},
256 <-- {"jsonrpc": "2.0",
257 "result": { "res1": "val1" },
260 Request producing a error::
262 --> {"jsonrpc": "2.0",
264 "params": {"context": {},
268 <-- {"jsonrpc": "2.0",
270 "message": "End user error message.",
271 "data": {"code": "codestring",
272 "debug": "traceback" } },
276 _request_type = "json"
278 def __init__(self, *args):
279 super(JsonRequest, self).__init__(*args)
281 self.jsonp_handler = None
283 args = self.httprequest.args
284 jsonp = args.get('jsonp')
287 request_id = args.get('id')
289 if jsonp and self.httprequest.method == 'POST':
290 # jsonp 2 steps step1 POST: save call
292 self.session.jsonp_requests[request_id] = self.httprequest.form['r']
293 self.session.modified = True
294 headers=[('Content-Type', 'text/plain; charset=utf-8')]
295 r = werkzeug.wrappers.Response(request_id, headers=headers)
297 self.jsonp_handler = handler
299 elif jsonp and args.get('r'):
301 request = args.get('r')
302 elif jsonp and request_id:
303 # jsonp 2 steps step2 GET: run and return result
304 request = self.session.jsonp_requests.pop(request_id, "")
307 request = self.httprequest.stream.read()
309 # Read POST content or POST Form Data named "request"
310 self.jsonrequest = simplejson.loads(request, object_hook=reject_nonliteral)
311 self.params = dict(self.jsonrequest.get("params", {}))
312 self.context = self.params.pop('context', self.session.context)
315 """ Calls the method asked for by the JSON-RPC2 or JSONP request
317 if self.jsonp_handler:
318 return self.jsonp_handler()
319 response = {"jsonrpc": "2.0" }
323 response['id'] = self.jsonrequest.get('id')
324 response["result"] = self._call_function(**self.params)
325 except AuthenticationError, e:
326 _logger.exception("Exception during JSON request handling.")
327 se = serialize_exception(e)
330 'message': "OpenERP Session Invalid",
334 _logger.exception("Exception during JSON request handling.")
335 se = serialize_exception(e)
338 'message': "OpenERP Server Error",
342 response["error"] = error
345 # If we use jsonp, that's mean we are called from another host
346 # Some browser (IE and Safari) do no allow third party cookies
347 # We need then to manage http sessions manually.
348 response['session_id'] = self.session_id
349 mime = 'application/javascript'
350 body = "%s(%s);" % (self.jsonp, simplejson.dumps(response),)
352 mime = 'application/json'
353 body = simplejson.dumps(response)
355 r = werkzeug.wrappers.Response(body, headers=[('Content-Type', mime), ('Content-Length', len(body))])
358 def serialize_exception(e):
360 "name": type(e).__module__ + "." + type(e).__name__ if type(e).__module__ else type(e).__name__,
361 "debug": traceback.format_exc(),
362 "message": u"%s" % e,
363 "arguments": to_jsonable(e.args),
365 if isinstance(e, openerp.osv.osv.except_osv):
366 tmp["exception_type"] = "except_osv"
367 elif isinstance(e, openerp.exceptions.Warning):
368 tmp["exception_type"] = "warning"
369 elif isinstance(e, openerp.exceptions.AccessError):
370 tmp["exception_type"] = "access_error"
371 elif isinstance(e, openerp.exceptions.AccessDenied):
372 tmp["exception_type"] = "access_denied"
376 if isinstance(o, str) or isinstance(o,unicode) or isinstance(o, int) or isinstance(o, long) \
377 or isinstance(o, bool) or o is None or isinstance(o, float):
379 if isinstance(o, list) or isinstance(o, tuple):
380 return [to_jsonable(x) for x in o]
381 if isinstance(o, dict):
383 for k, v in o.items():
384 tmp[u"%s" % k] = to_jsonable(v)
392 Use the ``route()`` decorator instead.
395 base = f.__name__.lstrip('/')
396 if f.__name__ == "index":
398 return route([base, base + "/<path:_ignored_path>"], type="json", auth="user")(f)
400 class HttpRequest(WebRequest):
401 """ Regular GET/POST request
403 _request_type = "http"
405 def __init__(self, *args):
406 super(HttpRequest, self).__init__(*args)
407 params = dict(self.httprequest.args)
408 params.update(self.httprequest.form)
409 params.update(self.httprequest.files)
410 params.pop('session_id', None)
415 r = self._call_function(**self.params)
416 except werkzeug.exceptions.HTTPException, e:
419 _logger.exception("An exception occured during an http request")
420 se = serialize_exception(e)
423 'message': "OpenERP Server Error",
426 r = werkzeug.exceptions.InternalServerError(cgi.escape(simplejson.dumps(error)))
429 r = werkzeug.wrappers.Response(status=204) # no content
432 def make_response(self, data, headers=None, cookies=None):
433 """ Helper for non-HTML responses, or HTML responses with custom
434 response headers or cookies.
436 While handlers can just return the HTML markup of a page they want to
437 send as a string if non-HTML data is returned they need to create a
438 complete response object, or the returned data will not be correctly
439 interpreted by the clients.
441 :param basestring data: response body
442 :param headers: HTTP headers to set on the response
443 :type headers: ``[(name, value)]``
444 :param collections.Mapping cookies: cookies to set on the client
446 response = werkzeug.wrappers.Response(data, headers=headers)
448 for k, v in cookies.iteritems():
449 response.set_cookie(k, v)
452 def not_found(self, description=None):
453 """ Helper for 404 response, return its result from the method
455 return werkzeug.exceptions.NotFound(description)
461 Use the ``route()`` decorator instead.
464 base = f.__name__.lstrip('/')
465 if f.__name__ == "index":
467 return route([base, base + "/<path:_ignored_path>"], type="http", auth="user")(f)
469 #----------------------------------------------------------
470 # Local storage of requests
471 #----------------------------------------------------------
472 from werkzeug.local import LocalStack
474 _request_stack = LocalStack()
477 @contextlib.contextmanager
478 def set_request(req):
479 _request_stack.push(req)
486 request = _request_stack()
488 A global proxy that always redirect to the current request object.
491 #----------------------------------------------------------
492 # Controller registration with a metaclass
493 #----------------------------------------------------------
496 controllers_per_module = {}
498 class ControllerType(type):
499 def __init__(cls, name, bases, attrs):
500 super(ControllerType, cls).__init__(name, bases, attrs)
502 # flag old-style methods with req as first argument
503 for k, v in attrs.items():
504 if inspect.isfunction(v):
505 spec = inspect.getargspec(v)
506 first_arg = spec.args[1] if len(spec.args) >= 2 else None
507 if first_arg in ["req", "request"]:
508 v._first_arg_is_req = True
510 # store the controller in the controllers list
511 name_class = ("%s.%s" % (cls.__module__, cls.__name__), cls)
512 class_path = name_class[0].split(".")
513 if not class_path[:2] == ["openerp", "addons"]:
515 # we want to know all modules that have controllers
516 module = class_path[2]
517 # but we only store controllers directly inheriting from Controller
518 if not "Controller" in globals() or not Controller in bases:
520 controllers_per_module.setdefault(module, []).append(name_class)
522 class Controller(object):
523 __metaclass__ = ControllerType
525 #############################
527 #############################
529 class AuthenticationError(Exception):
532 class SessionExpiredException(Exception):
535 class Service(object):
538 Use ``openerp.netsvc.dispatch_rpc()`` instead.
540 def __init__(self, session, service_name):
541 self.session = session
542 self.service_name = service_name
544 def __getattr__(self, method):
545 def proxy_method(*args):
546 result = openerp.netsvc.dispatch_rpc(self.service_name, method, args)
553 Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
555 def __init__(self, session, model):
556 self.session = session
558 self.proxy = self.session.proxy('object')
560 def __getattr__(self, method):
561 self.session.assert_valid()
562 def proxy(*args, **kw):
563 # Can't provide any retro-compatibility for this case, so we check it and raise an Exception
564 # to tell the programmer to adapt his code
565 if not request.db or not request.uid or self.session.db != request.db \
566 or self.session.uid != request.uid:
567 raise Exception("Trying to use Model with badly configured database or user.")
569 mod = request.registry.get(self.model)
570 if method.startswith('_'):
571 raise Exception("Access denied")
572 meth = getattr(mod, method)
574 result = meth(cr, request.uid, *args, **kw)
577 if isinstance(result, list) and len(result) > 0 and "id" in result[0]:
581 result = [index[x] for x in args[0] if x in index]
585 class OpenERPSession(werkzeug.contrib.sessions.Session):
586 def __init__(self, *args, **kwargs):
588 self.modified = False
589 super(OpenERPSession, self).__init__(*args, **kwargs)
591 self._default_values()
592 self.modified = False
594 def __getattr__(self, attr):
595 return self.get(attr, None)
596 def __setattr__(self, k, v):
597 if getattr(self, "inited", False):
599 object.__getattribute__(self, k)
601 return self.__setitem__(k, v)
602 object.__setattr__(self, k, v)
604 def authenticate(self, db, login=None, password=None, uid=None):
606 Authenticate the current user with the given db, login and password. If successful, store
607 the authentication parameters in the current session and request.
609 :param uid: If not None, that user id will be used instead the login to authenticate the user.
613 wsgienv = request.httprequest.environ
615 base_location=request.httprequest.url_root.rstrip('/'),
616 HTTP_HOST=wsgienv['HTTP_HOST'],
617 REMOTE_ADDR=wsgienv['REMOTE_ADDR'],
619 uid = openerp.netsvc.dispatch_rpc('common', 'authenticate', [db, login, password, env])
621 security.check(db, uid, password)
625 self.password = password
627 request.disable_db = False
629 if uid: self.get_context()
632 def check_security(self):
634 Chech the current authentication parameters to know if those are still valid. This method
635 should be called at each request. If the authentication fails, a ``SessionExpiredException``
638 if not self.db or not self.uid:
639 raise SessionExpiredException("Session expired")
640 security.check(self.db, self.uid, self.password)
643 for k in self.keys():
645 self._default_values()
647 def _default_values(self):
648 self.setdefault("db", None)
649 self.setdefault("uid", None)
650 self.setdefault("login", None)
651 self.setdefault("password", None)
652 self.setdefault("context", {'tz': "UTC", "uid": None})
653 self.setdefault("jsonp_requests", {})
655 def get_context(self):
657 Re-initializes the current user's session context (based on
658 his preferences) by calling res.users.get_context() with the old
661 :returns: the new context
663 assert self.uid, "The user needs to be logged-in to initialize his context"
664 self.context = request.registry.get('res.users').context_get(request.cr, request.uid) or {}
665 self.context['uid'] = self.uid
666 self._fix_lang(self.context)
669 def _fix_lang(self, context):
670 """ OpenERP provides languages which may not make sense and/or may not
671 be understood by the web client's libraries.
675 :param dict context: context to fix
677 lang = context['lang']
679 # inane OpenERP locale
683 # lang to lang_REGION (datejs only handles lang_REGION, no bare langs)
684 if lang in babel.core.LOCALE_ALIASES:
685 lang = babel.core.LOCALE_ALIASES[lang]
687 context['lang'] = lang or 'en_US'
690 Damn properties for retro-compatibility. All of that is deprecated, all
697 def _db(self, value):
703 def _uid(self, value):
709 def _login(self, value):
715 def _password(self, value):
716 self.password = value
718 def send(self, service_name, method, *args):
721 Use ``openerp.netsvc.dispatch_rpc()`` instead.
723 return openerp.netsvc.dispatch_rpc(service_name, method, args)
725 def proxy(self, service):
728 Use ``openerp.netsvc.dispatch_rpc()`` instead.
730 return Service(self, service)
732 def assert_valid(self, force=False):
735 Use ``check_security()`` instead.
737 Ensures this session is valid (logged into the openerp server)
739 if self.uid and not force:
741 # TODO use authenticate instead of login
742 self.uid = self.proxy("common").login(self.db, self.login, self.password)
744 raise AuthenticationError("Authentication failure")
746 def ensure_valid(self):
749 Use ``check_security()`` instead.
753 self.assert_valid(True)
757 def execute(self, model, func, *l, **d):
760 Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
762 model = self.model(model)
763 r = getattr(model, func)(*l, **d)
766 def exec_workflow(self, model, id, signal):
769 Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
772 r = self.proxy('object').exec_workflow(self.db, self.uid, self.password, model, signal, id)
775 def model(self, model):
778 Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
780 Get an RPC proxy for the object ``model``, bound to this session.
782 :param model: an OpenERP model name
784 :rtype: a model object
787 raise SessionExpiredException("Session expired")
789 return Model(self, model)
791 def session_gc(session_store):
792 if random.random() < 0.001:
793 # we keep session one week
794 last_week = time.time() - 60*60*24*7
795 for fname in os.listdir(session_store.path):
796 path = os.path.join(session_store.path, fname)
798 if os.path.getmtime(path) < last_week:
803 #----------------------------------------------------------
805 #----------------------------------------------------------
806 # Add potentially missing (older ubuntu) font mime types
807 mimetypes.add_type('application/font-woff', '.woff')
808 mimetypes.add_type('application/vnd.ms-fontobject', '.eot')
809 mimetypes.add_type('application/x-font-ttf', '.ttf')
811 class DisableCacheMiddleware(object):
812 def __init__(self, app):
814 def __call__(self, environ, start_response):
815 def start_wrapped(status, headers):
816 referer = environ.get('HTTP_REFERER', '')
817 parsed = urlparse.urlparse(referer)
818 debug = parsed.query.count('debug') >= 1
821 unwanted_keys = ['Last-Modified']
823 new_headers = [('Cache-Control', 'no-cache')]
824 unwanted_keys += ['Expires', 'Etag', 'Cache-Control']
827 if k not in unwanted_keys:
828 new_headers.append((k, v))
830 start_response(status, new_headers)
831 return self.app(environ, start_wrapped)
836 username = pwd.getpwuid(os.geteuid()).pw_name
839 username = getpass.getuser()
842 path = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
845 except OSError as exc:
846 if exc.errno == errno.EEXIST:
847 # directory exists: ensure it has the correct permissions
848 # this will fail if the directory is not owned by the current user
855 """Root WSGI application for the OpenERP Web Client.
861 self.no_db_router = None
865 # Setup http sessions
866 path = session_path()
867 self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)
868 _logger.debug('HTTP sessions stored in: %s', path)
871 def __call__(self, environ, start_response):
872 """ Handle a WSGI request
874 return self.dispatch(environ, start_response)
876 def dispatch(self, environ, start_response):
878 Performs the actual WSGI dispatching for the application.
881 httprequest = werkzeug.wrappers.Request(environ)
882 httprequest.parameter_storage_class = werkzeug.datastructures.ImmutableDict
883 httprequest.app = self
885 session_gc(self.session_store)
887 sid = httprequest.args.get('session_id')
888 explicit_session = True
890 sid = httprequest.headers.get("X-Openerp-Session-Id")
892 sid = httprequest.cookies.get('session_id')
893 explicit_session = False
895 httprequest.session = self.session_store.new()
897 httprequest.session = self.session_store.get(sid)
899 self._find_db(httprequest)
901 if not "lang" in httprequest.session.context:
902 lang = httprequest.accept_languages.best or "en_US"
903 lang = babel.core.LOCALE_ALIASES.get(lang, lang).replace('-', '_')
904 httprequest.session.context["lang"] = lang
906 request = self._build_request(httprequest)
910 openerp.modules.registry.RegistryManager.check_registry_signaling(db)
912 with set_request(request):
914 result = request.dispatch()
917 openerp.modules.registry.RegistryManager.signal_caches_change(db)
919 if isinstance(result, basestring):
920 headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))]
921 response = werkzeug.wrappers.Response(result, headers=headers)
925 if httprequest.session.should_save:
926 self.session_store.save(httprequest.session)
927 if not explicit_session and hasattr(response, 'set_cookie'):
928 response.set_cookie('session_id', httprequest.session.sid, max_age=90 * 24 * 60 * 60)
930 return response(environ, start_response)
931 except werkzeug.exceptions.HTTPException, e:
932 return e(environ, start_response)
934 def _find_db(self, httprequest):
935 db = db_monodb(httprequest)
936 if db != httprequest.session.db:
937 httprequest.session.logout()
938 httprequest.session.db = db
940 def _build_request(self, httprequest):
941 if httprequest.args.get('jsonp'):
942 return JsonRequest(httprequest)
944 if httprequest.mimetype == "application/json":
945 return JsonRequest(httprequest)
947 return HttpRequest(httprequest)
949 def load_addons(self):
950 """ Load all addons from addons patch containg static files and
951 controllers and configure them. """
953 for addons_path in openerp.modules.module.ad_paths:
954 for module in sorted(os.listdir(str(addons_path))):
955 if module not in addons_module:
956 manifest_path = os.path.join(addons_path, module, '__openerp__.py')
957 path_static = os.path.join(addons_path, module, 'static')
958 if os.path.isfile(manifest_path) and os.path.isdir(path_static):
959 manifest = ast.literal_eval(open(manifest_path).read())
960 manifest['addons_path'] = addons_path
961 _logger.debug("Loading %s", module)
962 if 'openerp.addons' in sys.modules:
963 m = __import__('openerp.addons.' + module)
965 m = __import__(module)
966 addons_module[module] = m
967 addons_manifest[module] = manifest
968 self.statics['/%s/static' % module] = path_static
970 app = werkzeug.wsgi.SharedDataMiddleware(self.dispatch, self.statics)
971 self.dispatch = DisableCacheMiddleware(app)
973 def _build_router(self, db):
974 _logger.info("Generating routing configuration for database %s" % db)
975 routing_map = routing.Map(strict_slashes=False)
977 def gen(modules, nodb_only):
978 for module in modules:
979 for v in controllers_per_module[module]:
982 subclasses = cls.__subclasses__()
983 subclasses = [c for c in subclasses if c.__module__.startswith('openerp.addons.') and
984 c.__module__.split(".")[2] in modules]
986 name = "%s (extended by %s)" % (cls.__name__, ', '.join(sub.__name__ for sub in subclasses))
987 cls = type(name, tuple(reversed(subclasses)), {})
990 members = inspect.getmembers(o)
991 for mk, mv in members:
992 if inspect.ismethod(mv) and getattr(mv, 'exposed', False) and \
993 nodb_only == (getattr(mv, "auth", "none") == "none"):
994 for url in mv.routes:
995 if getattr(mv, "combine", False):
996 url = o._cp_path.rstrip('/') + '/' + url.lstrip('/')
997 if url.endswith("/") and len(url) > 1:
999 routing_map.add(routing.Rule(url, endpoint=mv))
1001 modules_set = set(controllers_per_module.keys()) - set(['web'])
1002 # building all none methods
1003 gen(["web"] + sorted(modules_set), True)
1007 registry = openerp.modules.registry.RegistryManager.get(db)
1008 with registry.cursor() as cr:
1009 m = registry.get('ir.module.module')
1010 ids = m.search(cr, openerp.SUPERUSER_ID, [('state', '=', 'installed'), ('name', '!=', 'web')])
1011 installed = set(x['name'] for x in m.read(cr, 1, ids, ['name']))
1012 modules_set = modules_set & installed
1014 # building all other methods
1015 gen(["web"] + sorted(modules_set), False)
1019 def get_db_router(self, db):
1021 router = self.no_db_router
1023 router = getattr(openerp.modules.registry.RegistryManager.get(db), "werkzeug_http_router", None)
1025 router = self._build_router(db)
1027 self.no_db_router = router
1029 openerp.modules.registry.RegistryManager.get(db).werkzeug_http_router = router
1032 def find_handler(self):
1034 Tries to discover the controller handling the request for the path specified in the request.
1036 path = request.httprequest.path
1037 urls = self.get_db_router(request.db).bind("")
1038 func, arguments = urls.match(path)
1039 arguments = dict([(k, v) for k, v in arguments.items() if not k.startswith("_ignored_")])
1041 @service_model.check
1042 def checked_call(dbname, *a, **kw):
1043 return func(*a, **kw)
1045 def nfunc(*args, **kwargs):
1046 kwargs.update(arguments)
1047 if getattr(func, '_first_arg_is_req', False):
1048 args = (request,) + args
1051 return checked_call(request.db, *args, **kwargs)
1052 return func(*args, **kwargs)
1054 request.func = nfunc
1055 request.auth_method = getattr(func, "auth", "user")
1056 request.func_request_type = func.exposed
1060 def db_list(force=False, httprequest=None):
1061 httprequest = httprequest or request.httprequest
1062 dbs = openerp.netsvc.dispatch_rpc("db", "list", [force])
1063 h = httprequest.environ['HTTP_HOST'].split(':')[0]
1065 r = openerp.tools.config['dbfilter'].replace('%h', h).replace('%d', d)
1066 dbs = [i for i in dbs if re.match(r, i)]
1069 def db_monodb(httprequest=None):
1071 Magic function to find the current database.
1073 Implementation details:
1078 Returns ``None`` if the magic is not magic enough.
1080 httprequest = httprequest or request.httprequest
1084 dbs = db_list(True, httprequest)
1086 # try the db already in the session
1087 db_session = httprequest.session.db
1088 if db_session in dbs:
1091 # if dbfilters was specified when launching the server and there is
1092 # only one possible db, we take that one
1093 if openerp.tools.config['dbfilter'] != ".*" and len(dbs) == 1:
1097 class CommonController(Controller):
1099 @route('/jsonrpc', type='json', auth="none")
1100 def jsonrpc(self, service, method, args):
1101 """ Method used by client APIs to contact OpenERP. """
1102 return openerp.netsvc.dispatch_rpc(service, method, args)
1104 @route('/gen_session_id', type='json', auth="none")
1105 def gen_session_id(self):
1106 nsession = root.session_store.new()
1109 def wsgi_postload():
1112 openerp.wsgi.register_wsgi_handler(root)