*: base_setup, hr_timesheet, mail, partner_autocomplete, web_tour Start odoo without -d and with a --dbfilter that allows multiple databases. Via JSON-RPC access the /web/session/authenticate route providing a non-filtered database and valid credentials. Traceback, `request.env` is None. Since httpocalypse the initialization of the ORM (cursor, registry, environment) is greedy. It means that the connection to the database is established very early during the request routing or skip altogether in case no dbname was known at that time. This contrast with prepocalypse where the various ORM thingies were lazily setup the first time they were accessed. This changement has an important implication regarding authentication. In prepocalypse, thanks to the lazy approache, a cursor/registry/env would be setup on the database you just login upon using the `request.env` for the first time. This was very nice in this regard but had other problems. Since httpocalypse such operation is no more possible. Devs must initialize and use their own cursor/registry/env in case they authenticate on another database than the one `request.cr` is (maybe) connected to. The `/web/session/authenticate` controller is an example of such case. It crates its own cr/registry/environment after authentication. The problem the controller uses `ir.http.session_info` and that not all overrides were updated to use `self.env` (=the env created in the web controller) instead of `request.env` (=the missing env of the request). closes odoo/odoo#108063 X-original-commit: 7b9bd9d37731fae724dc5d91da656dab70aa9ad4 Related: odoo/enterprise#35012 Signed-off-by: Julien Castiaux <juc@odoo.com>
180 lines
7.6 KiB
Python
180 lines
7.6 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import hashlib
|
|
import json
|
|
import logging
|
|
|
|
import odoo
|
|
from odoo import api, http, models
|
|
from odoo.http import request
|
|
from odoo.tools import file_open, image_process, ustr
|
|
from odoo.tools.misc import str2bool
|
|
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
"""
|
|
Debug mode is stored in session and should always be a string.
|
|
It can be activated with an URL query string `debug=<mode>` where mode
|
|
is either:
|
|
- 'tests' to load tests assets
|
|
- 'assets' to load assets non minified
|
|
- any other truthy value to enable simple debug mode (to show some
|
|
technical feature, to show complete traceback in frontend error..)
|
|
- any falsy value to disable debug mode
|
|
|
|
You can use any truthy/falsy value from `str2bool` (eg: 'on', 'f'..)
|
|
Multiple debug modes can be activated simultaneously, separated with a
|
|
comma (eg: 'tests, assets').
|
|
"""
|
|
ALLOWED_DEBUG_MODES = ['', '1', 'assets', 'tests', 'disable-t-cache']
|
|
|
|
|
|
class Http(models.AbstractModel):
|
|
_inherit = 'ir.http'
|
|
|
|
bots = ["bot", "crawl", "slurp", "spider", "curl", "wget", "facebookexternalhit", "whatsapp", "trendsmapresolver", "pinterest", "instagram"]
|
|
|
|
@classmethod
|
|
def is_a_bot(cls):
|
|
user_agent = request.httprequest.user_agent.string.lower()
|
|
# We don't use regexp and ustr voluntarily
|
|
# timeit has been done to check the optimum method
|
|
return any(bot in user_agent for bot in cls.bots)
|
|
|
|
@classmethod
|
|
def _handle_debug(cls):
|
|
debug = request.httprequest.args.get('debug')
|
|
if debug is not None:
|
|
request.session.debug = ','.join(
|
|
mode if mode in ALLOWED_DEBUG_MODES
|
|
else '1' if str2bool(mode, mode)
|
|
else ''
|
|
for mode in (debug or '').split(',')
|
|
)
|
|
|
|
@classmethod
|
|
def _pre_dispatch(cls, rule, args):
|
|
super()._pre_dispatch(rule, args)
|
|
cls._handle_debug()
|
|
|
|
def webclient_rendering_context(self):
|
|
return {
|
|
'menu_data': request.env['ir.ui.menu'].load_menus(request.session.debug),
|
|
'session_info': self.session_info(),
|
|
}
|
|
|
|
def session_info(self):
|
|
user = self.env.user
|
|
session_uid = request.session.uid
|
|
version_info = odoo.service.common.exp_version()
|
|
|
|
if session_uid:
|
|
user_context = dict(self.env['res.users'].context_get())
|
|
if user_context != request.session.context:
|
|
request.session.context = user_context
|
|
else:
|
|
user_context = {}
|
|
|
|
IrConfigSudo = self.env['ir.config_parameter'].sudo()
|
|
max_file_upload_size = int(IrConfigSudo.get_param(
|
|
'web.max_file_upload_size',
|
|
default=128 * 1024 * 1024, # 128MiB
|
|
))
|
|
mods = odoo.conf.server_wide_modules or []
|
|
if request.db:
|
|
mods = list(request.registry._init_modules) + mods
|
|
session_info = {
|
|
"uid": session_uid,
|
|
"is_system": user._is_system() if session_uid else False,
|
|
"is_admin": user._is_admin() if session_uid else False,
|
|
"user_context": user_context,
|
|
"db": self.env.cr.dbname,
|
|
"server_version": version_info.get('server_version'),
|
|
"server_version_info": version_info.get('server_version_info'),
|
|
"support_url": "https://www.odoo.com/buy",
|
|
"name": user.name,
|
|
"username": user.login,
|
|
"partner_display_name": user.partner_id.display_name,
|
|
"company_id": user.company_id.id if session_uid else None, # YTI TODO: Remove this from the user context
|
|
"partner_id": user.partner_id.id if session_uid and user.partner_id else None,
|
|
"web.base.url": IrConfigSudo.get_param('web.base.url', default=''),
|
|
"active_ids_limit": int(IrConfigSudo.get_param('web.active_ids_limit', default='20000')),
|
|
'profile_session': request.session.profile_session,
|
|
'profile_collectors': request.session.profile_collectors,
|
|
'profile_params': request.session.profile_params,
|
|
"max_file_upload_size": max_file_upload_size,
|
|
"home_action_id": user.action_id.id,
|
|
"cache_hashes": {
|
|
"translations": self.env['ir.http'].sudo().get_web_translations_hash(
|
|
mods, request.session.context['lang']
|
|
) if session_uid else None,
|
|
},
|
|
"currencies": self.sudo().get_currencies(),
|
|
'bundle_params': {
|
|
'lang': request.session.context['lang'],
|
|
},
|
|
}
|
|
if request.session.debug:
|
|
session_info['bundle_params']['debug'] = request.session.debug
|
|
if self.env.user.has_group('base.group_user'):
|
|
# the following is only useful in the context of a webclient bootstrapping
|
|
# but is still included in some other calls (e.g. '/web/session/authenticate')
|
|
# to avoid access errors and unnecessary information, it is only included for users
|
|
# with access to the backend ('internal'-type users)
|
|
menus = self.env['ir.ui.menu'].load_menus(request.session.debug)
|
|
ordered_menus = {str(k): v for k, v in menus.items()}
|
|
menu_json_utf8 = json.dumps(ordered_menus, default=ustr, sort_keys=True).encode()
|
|
session_info['cache_hashes'].update({
|
|
"load_menus": hashlib.sha512(menu_json_utf8).hexdigest()[:64], # sha512/256
|
|
})
|
|
session_info.update({
|
|
# current_company should be default_company
|
|
"user_companies": {
|
|
'current_company': user.company_id.id,
|
|
'allowed_companies': {
|
|
comp.id: {
|
|
'id': comp.id,
|
|
'name': comp.name,
|
|
'sequence': comp.sequence,
|
|
} for comp in user.company_ids
|
|
},
|
|
},
|
|
"show_effect": True,
|
|
"display_switch_company_menu": user.has_group('base.group_multi_company') and len(user.company_ids) > 1,
|
|
})
|
|
return session_info
|
|
|
|
@api.model
|
|
def get_frontend_session_info(self):
|
|
user = self.env.user
|
|
session_uid = request.session.uid
|
|
session_info = {
|
|
'is_admin': user._is_admin() if session_uid else False,
|
|
'is_system': user._is_system() if session_uid else False,
|
|
'is_website_user': user._is_public() if session_uid else False,
|
|
'user_id': user.id if session_uid else False,
|
|
'is_frontend': True,
|
|
'profile_session': request.session.profile_session,
|
|
'profile_collectors': request.session.profile_collectors,
|
|
'profile_params': request.session.profile_params,
|
|
'show_effect': bool(request.env['ir.config_parameter'].sudo().get_param('base_setup.show_effect')),
|
|
'bundle_params': {
|
|
'lang': request.session.context['lang'],
|
|
},
|
|
}
|
|
if request.session.debug:
|
|
session_info['bundle_params']['debug'] = request.session.debug
|
|
if session_uid:
|
|
version_info = odoo.service.common.exp_version()
|
|
session_info.update({
|
|
'server_version': version_info.get('server_version'),
|
|
'server_version_info': version_info.get('server_version_info')
|
|
})
|
|
return session_info
|
|
|
|
def get_currencies(self):
|
|
Currency = self.env['res.currency']
|
|
currencies = Currency.search([]).read(['symbol', 'position', 'decimal_places'])
|
|
return {c['id']: {'symbol': c['symbol'], 'position': c['position'], 'digits': [69,c['decimal_places']]} for c in currencies}
|