).strip()
return result
-def db_list(req, force=False):
- proxy = req.session.proxy("db")
- dbs = proxy.list(force)
- h = req.httprequest.environ['HTTP_HOST'].split(':')[0]
- d = h.split('.')[0]
- r = openerp.tools.config['dbfilter'].replace('%h', h).replace('%d', d)
- dbs = [i for i in dbs if re.match(r, i)]
- return dbs
-
-def db_monodb_redirect(req):
- return db_redirect(req, not config['list_db'])
-
-def db_redirect(req, match_first_only_if_unique):
- db = False
- redirect = False
-
- dbs = db_list(req, True)
-
- # 1 try the db in the url
- db_url = req.params.get('db')
- if db_url and db_url in dbs:
- return (db_url, False)
-
- # 2 use the database from the cookie if it's listable and still listed
- cookie_db = req.httprequest.cookies.get('last_used_database')
- if cookie_db in dbs:
- db = cookie_db
-
- # 3 use the first db if user can list databases
- if dbs and not db and (not match_first_only_if_unique or len(dbs) == 1):
- db = dbs[0]
-
- # redirect to the chosen db if multiple are available
- if db and len(dbs) > 1:
- query = dict(urlparse.parse_qsl(req.httprequest.query_string, keep_blank_values=True))
- query.update({'db': db})
- redirect = req.httprequest.path + '?' + urllib.urlencode(query)
- return (db, redirect)
-
-def db_monodb(req):
- # if only one db exists, return it else return False
- return db_redirect(req, True)[0]
-
-def redirect_with_hash(req, url, code=303):
- # Most IE and Safari versions decided not to preserve location.hash upon
- # redirect. And even if IE10 pretends to support it, it still fails
- # inexplicably in case of multiple redirects (and we do have some).
- # See extensive test page at http://greenbytes.de/tech/tc/httpredirects/
- return "<html><head><script>window.location = '%s' + location.hash;</script></head></html>" % url
+db_list = http.db_list
+
+db_monodb = http.db_monodb
+
+def serialize_exception(f):
+ @functools.wraps(f)
+ def wrap(*args, **kwargs):
+ try:
+ return f(*args, **kwargs)
+ except Exception, e:
+ _logger.exception("An exception occured during an http request")
+ se = _serialize_exception(e)
+ error = {
+ 'code': 200,
+ 'message': "OpenERP Server Error",
+ 'data': se
+ }
+ return werkzeug.exceptions.InternalServerError(simplejson.dumps(error))
+ return wrap
+
+def redirect_with_hash(*args, **kw):
+ """
+ .. deprecated:: 8.0
+
+ Use the ``http.redirect_with_hash()`` function instead.
+ """
+ return http.redirect_with_hash(*args, **kw)
+
+def ensure_db(redirect='/web/database/selector'):
+ # This helper should be used in web client auth="none" routes
+ # if those routes needs a db to work with.
+ # If the heuristics does not find any database, then the users will be
+ # redirected to db selector or any url specified by `redirect` argument.
+ # If the db is taken out of a query parameter, it will be checked against
+ # `http.db_filter()` in order to ensure it's legit and thus avoid db
+ # forgering that could lead to xss attacks.
+ db = request.params.get('db')
+
+ # Ensure db is legit
+ if db and db not in http.db_filter([db]):
+ db = None
+
+ if db and not request.session.db:
+ # User asked a specific database on a new session.
+ # That mean the nodb router has been used to find the route
+ # Depending on installed module in the database, the rendering of the page
+ # may depend on data injected by the database route dispatcher.
+ # Thus, we redirect the user to the same page but with the session cookie set.
+ # This will force using the database route dispatcher...
+ r = request.httprequest
+ url_redirect = r.base_url
+ if r.query_string:
+ # Can't use werkzeug.wrappers.BaseRequest.url with encoded hashes:
+ # https://github.com/amigrave/werkzeug/commit/b4a62433f2f7678c234cdcac6247a869f90a7eb7
+ url_redirect += '?' + r.query_string
+ response = werkzeug.utils.redirect(url_redirect, 302)
+ request.session.db = db
+ response = r.app.get_response(r, response, explicit_session=False)
+ werkzeug.exceptions.abort(response)
+ return
+
+ # if db not provided, use the session one
- if not db:
++ if not db and http.db_filter([request.session.db]):
+ db = request.session.db
+
+ # if no database provided and no database in session, use monodb
+ if not db:
+ db = db_monodb(request.httprequest)
+
+ # if no db can be found til here, send to the database selector
+ # the database selector will redirect to database manager if needed
+ if not db:
+ werkzeug.exceptions.abort(werkzeug.utils.redirect(redirect, 303))
+
+ # always switch the session to the computed db
+ if db != request.session.db:
+ request.session.logout()
+
+ request.session.db = db
def module_topological_sort(modules):
""" Return a list of module names sorted so that their dependencies of the
</html>
"""
-class Home(openerpweb.Controller):
- _cp_path = '/'
+def render_bootstrap_template(db, template, values=None, debug=False, lazy=False, **kw):
+ if request and request.debug:
+ debug = True
+ if values is None:
+ values = {}
+ values.update(kw)
+ values['debug'] = debug
+ values['current_db'] = db
+ try:
+ values['databases'] = http.db_list()
+ except openerp.exceptions.AccessDenied:
+ values['databases'] = None
- @openerpweb.httprequest
- def index(self, req, s_action=None, db=None, **kw):
- db, redir = db_monodb_redirect(req)
- if redir:
- return redirect_with_hash(req, redir)
+ for res in ['js', 'css']:
+ if res not in values:
+ values[res] = manifest_list(res, db=db, debug=debug)
- js = "\n ".join('<script type="text/javascript" src="%s"></script>' % i for i in manifest_list(req, 'js', db=db))
- css = "\n ".join('<link rel="stylesheet" href="%s">' % i for i in manifest_list(req, 'css', db=db))
+ if 'modules' not in values:
+ values['modules'] = module_boot(db=db)
+ values['modules'] = simplejson.dumps(values['modules'])
- r = html_template % {
- 'js': js,
- 'css': css,
- 'modules': simplejson.dumps(module_boot(req, db=db)),
- 'init': 'var wc = new s.web.WebClient();wc.appendTo($(document.body));'
- }
- return r
+ def callback(template, values):
+ registry = openerp.modules.registry.RegistryManager.get(db)
+ with registry.cursor() as cr:
+ view_obj = registry["ir.ui.view"]
+ uid = request.uid or openerp.SUPERUSER_ID
+ return view_obj.render(cr, uid, template, values)
+ if lazy:
+ return LazyResponse(callback, template=template, values=values)
+ else:
+ return callback(template, values)
+
+class Home(http.Controller):
+
+ @http.route('/', type='http', auth="none")
+ def index(self, s_action=None, db=None, **kw):
+ return http.local_redirect('/web', query=request.params, keep_hash=True)
- @openerpweb.httprequest
- def login(self, req, db, login, key):
- if db not in db_list(req, True):
+ @http.route('/web', type='http', auth="none")
+ def web_client(self, s_action=None, **kw):
+ ensure_db()
+
+ if request.session.uid:
+ if kw.get('redirect'):
+ return werkzeug.utils.redirect(kw.get('redirect'), 303)
+
+ html = render_bootstrap_template(request.session.db, "web.webclient_bootstrap")
+ return request.make_response(html, {'Cache-Control': 'no-cache', 'Content-Type': 'text/html; charset=utf-8'})
+ else:
+ return login_redirect()
+
+ @http.route('/web/login', type='http', auth="none")
+ def web_login(self, redirect=None, **kw):
+ ensure_db()
+
+ if request.httprequest.method == 'GET' and redirect and request.session.uid:
+ return http.redirect_with_hash(redirect)
+
+ values = request.params.copy()
+ if not redirect:
+ redirect = '/web?' + request.httprequest.query_string
+ values['redirect'] = redirect
+ if request.httprequest.method == 'POST':
+ uid = request.session.authenticate(request.session.db, request.params['login'], request.params['password'])
+ if uid is not False:
+ return http.redirect_with_hash(redirect)
+ values['error'] = "Wrong login/password"
+ return render_bootstrap_template(request.session.db, 'web.login', values, lazy=True)
+
+ @http.route('/login', type='http', auth="none")
+ def login(self, db, login, key, redirect="/web", **kw):
++ if not http.db_filter([db]):
+ return werkzeug.utils.redirect('/', 303)
- return login_and_redirect(req, db, login, key)
+ return login_and_redirect(db, login, key, redirect_url=redirect)
-class WebClient(openerpweb.Controller):
- _cp_path = "/web/webclient"
+class WebClient(http.Controller):
- @openerpweb.jsonrequest
- def csslist(self, req, mods=None):
- return manifest_list(req, 'css', mods=mods)
+ @http.route('/web/webclient/csslist', type='json', auth="none")
+ def csslist(self, mods=None):
+ return manifest_list('css', mods=mods)
- @openerpweb.jsonrequest
- def jslist(self, req, mods=None):
- return manifest_list(req, 'js', mods=mods)
+ @http.route('/web/webclient/jslist', type='json', auth="none")
+ def jslist(self, mods=None):
+ return manifest_list('js', mods=mods)
- @openerpweb.jsonrequest
- def qweblist(self, req, mods=None):
- return manifest_list(req, 'qweb', mods=mods)
+ @http.route('/web/webclient/qweblist', type='json', auth="none")
+ def qweblist(self, mods=None):
+ return manifest_list('qweb', mods=mods)
- @openerpweb.httprequest
- def css(self, req, mods=None, db=None):
- files = list(manifest_glob(req, 'css', addons=mods, db=db))
+ @http.route('/web/webclient/css', type='http', auth="none")
+ def css(self, mods=None, db=None):
+ files = list(manifest_glob('css', addons=mods, db=db))
last_modified = get_last_modified(f[0] for f in files)
- if req.httprequest.if_modified_since and req.httprequest.if_modified_since >= last_modified:
+ if request.httprequest.if_modified_since and request.httprequest.if_modified_since >= last_modified:
return werkzeug.wrappers.Response(status=304)
file_map = dict(files)
font-size: 95%;
line-height: 1.2em;
}
-.openerp .oe_debug_view_log label {
- display: block;
- width: 49%;
- text-align: right;
- float: left;
+.openerp .navbar {
+ min-height: 32px;
+ margin-bottom: 0px;
+ border: none;
+ z-index: 1;
+ position: static;
+ background-color: #414141;
+ background-color: #454343;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#646060), to(#262626));
+ background-image: -webkit-linear-gradient(top, #646060, #262626);
+ background-image: -moz-linear-gradient(top, #646060, #262626);
+ background-image: -ms-linear-gradient(top, #646060, #262626);
+ background-image: -o-linear-gradient(top, #646060, #262626);
+ background-image: linear-gradient(to bottom, #646060, #262626);
+}
+.openerp .navbar-default .navbar-nav li a:hover, .openerp .navbar-default .navbar-nav li a:focus {
+ background: rgba(0, 0, 0, 0.3);
+}
+.openerp .navbar-default .navbar-nav .open > a, .openerp .navbar-default .navbar-nav a:hover, .openerp .navbar-default .navbar-nav a:focus {
+ background: rgba(0, 0, 0, 0.3) !important;
+}
+.openerp .navbar-default .navbar-nav .dropdown > a .caret {
+ border-top-color: #777777 !important;
+ border-bottom-color: #777777 !important;
+}
+.openerp .navbar-nav li a {
+ padding: 4px 32px 4px 12px;
+}
+.openerp .oe_navbar .dropdown-menu {
+ font-size: 13px;
+ padding: 4px 0;
+ background: #333333 !important;
+ background: rgba(37, 37, 37, 0.9) !important;
+ border-color: #999999;
+ border-color: rgba(0, 0, 0, 0.2);
+ background-color: #414141;
+ text-shadow: none;
+ background-color: #454343;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#646060), to(#262626));
+ background-image: -webkit-linear-gradient(top, #646060, #262626);
+ background-image: -moz-linear-gradient(top, #646060, #262626);
+ background-image: -ms-linear-gradient(top, #646060, #262626);
+ background-image: -o-linear-gradient(top, #646060, #262626);
+ background-image: linear-gradient(to bottom, #646060, #262626);
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+.openerp .oe_navbar .dropdown-menu li a, .openerp .oe_navbar .dropdown-menu li a:hover, .openerp .oe_navbar .dropdown-menu li a:focus {
+ color: #eeeeee;
+}
+.openerp .oe_view_manager_new .oe_form_nosheet {
+ margin-top: 8px;
+}
+.openerp .oe_view_manager_new .oe_form_nosheet .oe_form_label {
+ font-weight: normal;
+}
+.openerp .nav li > a {
+ padding: 3px 4px 2px 18px;
+ color: #4c4c4c;
+}
+.openerp .nav nav-pills.nav-stacked > li > ul {
+ padding-left: 16px;
+}
+.openerp .nav-pills > li.active > a, .openerp a.list-group-item.active > a {
+ background-color: #7c7bad;
+ color: white;
+ border-radius: 0;
+}
+.openerp .nav-pills > li.active a:hover, .openerp .nav-pills > li.active a:focus, .openerp a.list-group-item.active a:hover, .openerp a.list-group-item.active a:focus {
+ background-color: #7c7bad;
+}
+.openerp .nav-pills > li.active .badge, .openerp a.list-group-item.active .badge {
+ background-color: white;
+ color: #7c7bad;
+ text-shadow: none;
+}
+.openerp .badge {
+ font-weight: normal;
+ font-size: 11px;
+ background-color: #7c7bad;
+}
+.openerp button, .openerp body {
+ line-height: normal;
+}
+.openerp h1, .openerp h2 {
font-weight: bold;
- color: #000099;
}
-.openerp .oe_debug_view_log span {
+.openerp h3 {
+ font-size: 1.17em;
+ font-weight: bold;
+}
+.openerp p {
display: block;
- width: 49%;
- float: right;
- color: #333333;
+ -webkit-margin-before: 1em;
+ -webkit-margin-after: 1em;
+ -webkit-margin-start: 0px;
+ -webkit-margin-end: 0px;
+}
+.openerp pre {
+ background-color: white;
+ border: none;
+ padding: 10px 0 3px 0;
+}
+.openerp h5 {
+ font-weight: bold;
+ font-size: smaller;
+}
+.openerp .oe_form .oe_subtype label, .openerp .oe_subtype label {
+ font-weight: normal;
+}
+.openerp .oe_msg_subtype_check {
+ margin: 3px 3px 0 !important;
}
+.jqstooltip {
+ height: auto !important;
+ width: auto !important;
+ padding: 0;
+}
+
+@-moz-document url-prefix() {
+ .openerp .oe_searchview .oe_searchview_search {
+ top: -1px;
+ }
+ .openerp .oe_form_field_many2one .oe_m2o_cm_button {
+ line-height: 18px;
+ }
+ .openerp .oe_webclient .oe_star_on, .openerp .oe_webclient .oe_star_off {
+ top: 0px;
+ }
+}
-
.kitten-mode-activated {
background-size: cover;
background-attachment: fixed;