vanilla 19.0

This commit is contained in:
Ernad Husremovic 2025-10-08 10:49:46 +02:00
parent 991d2234ca
commit d1963a3c3a
3066 changed files with 1651266 additions and 922560 deletions

View file

@ -1,18 +1,12 @@
# 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
from odoo import api, models, fields
from odoo.http import request, DEFAULT_MAX_CONTENT_LENGTH
from odoo.tools import config
from odoo.tools.misc import hmac, 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
@ -27,10 +21,10 @@ 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']
ALLOWED_DEBUG_MODES = ['', '1', 'assets', 'tests']
class Http(models.AbstractModel):
class IrHttp(models.AbstractModel):
_inherit = 'ir.http'
bots = ["bot", "crawl", "slurp", "spider", "curl", "wget", "facebookexternalhit", "whatsapp", "trendsmapresolver", "pinterest", "instagram", "google-pagerenderer", "preview"]
@ -42,6 +36,12 @@ class Http(models.AbstractModel):
# timeit has been done to check the optimum method
return any(bot in user_agent for bot in cls.bots)
@classmethod
def _sanitize_cookies(cls, cookies):
super()._sanitize_cookies(cookies)
if cids := cookies.get('cids'):
cookies['cids'] = '-'.join(cids.split(','))
@classmethod
def _handle_debug(cls):
debug = request.httprequest.args.get('debug')
@ -58,12 +58,24 @@ class Http(models.AbstractModel):
super()._pre_dispatch(rule, args)
cls._handle_debug()
@classmethod
def _post_logout(cls):
super()._post_logout()
request.future_response.set_cookie('cids', max_age=0)
def webclient_rendering_context(self):
return {
'menu_data': request.env['ir.ui.menu'].load_menus(request.session.debug),
'color_scheme': self.color_scheme(),
'session_info': self.session_info(),
}
def color_scheme(self):
return "light"
@api.model
def lazy_session_info(self):
return {}
def session_info(self):
user = self.env.user
session_uid = request.session.uid
@ -79,55 +91,53 @@ class Http(models.AbstractModel):
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
default=DEFAULT_MAX_CONTENT_LENGTH,
))
mods = odoo.conf.server_wide_modules or []
if request.db:
mods = list(request.registry._init_modules) + mods
is_internal_user = user._is_internal()
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,
"is_public": user._is_public(),
"is_internal_user": is_internal_user,
"user_context": user_context,
"db": self.env.cr.dbname,
"registry_hash": hmac(self.env(su=True), "webclient-cache", self.env.registry.registry_sequence),
"user_settings": self.env['res.users.settings']._find_or_create_for_user(user)._res_users_settings_format(),
"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,
"quick_login": str2bool(IrConfigSudo.get_param('web.quick_login', default=True), True),
"partner_write_date": fields.Datetime.to_string(user.partner_id.write_date),
"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,
'profile_session': request.session.get('profile_session'),
'profile_collectors': request.session.get('profile_collectors'),
'profile_params': request.session.get('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(),
"currencies": self.env['res.currency'].get_all_currencies(),
'bundle_params': {
'lang': request.session.context['lang'],
},
'test_mode': config['test_enable'],
'view_info': self.env['ir.ui.view'].get_view_info(),
'groups': {
'base.group_allow_export': user.has_group('base.group_allow_export') if session_uid else False,
},
}
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'].with_context(lang=request.session.context['lang']).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
})
if is_internal_user:
# We need sudo since a user may not have access to ancestor companies
# We use `_get_company_ids` because it is cached and we sudo it because env.user return a sudo user.
user_companies = self.env['res.company'].browse(user._get_company_ids()).sudo()
disallowed_ancestor_companies_sudo = user_companies.parent_ids - user_companies
all_companies_in_hierarchy_sudo = disallowed_ancestor_companies_sudo + user_companies
session_info.update({
# current_company should be default_company
"user_companies": {
@ -137,11 +147,22 @@ class Http(models.AbstractModel):
'id': comp.id,
'name': comp.name,
'sequence': comp.sequence,
} for comp in user.company_ids
'child_ids': (comp.child_ids & user_companies).ids,
'parent_id': comp.parent_id.id,
'currency_id': comp.currency_id.id,
} for comp in user_companies
},
'disallowed_ancestor_companies': {
comp.id: {
'id': comp.id,
'name': comp.name,
'sequence': comp.sequence,
'child_ids': (comp.child_ids & all_companies_in_hierarchy_sudo).ids,
'parent_id': comp.parent_id.id,
} for comp in disallowed_ancestor_companies_sudo
},
},
"show_effect": True,
"display_switch_company_menu": user.has_group('base.group_multi_company') and len(user.company_ids) > 1,
})
return session_info
@ -152,16 +173,22 @@ class Http(models.AbstractModel):
session_info = {
'is_admin': user._is_admin() if session_uid else False,
'is_system': user._is_system() if session_uid else False,
'is_public': user._is_public(),
"is_internal_user": user._is_internal(),
'is_website_user': user._is_public() if session_uid else False,
'user_id': user.id if session_uid else False,
'uid': session_uid,
"registry_hash": hmac(self.env(su=True), "webclient-cache", self.env.registry.registry_sequence),
'is_frontend': True,
'profile_session': request.session.profile_session,
'profile_collectors': request.session.profile_collectors,
'profile_params': request.session.profile_params,
'profile_session': request.session.get('profile_session'),
'profile_collectors': request.session.get('profile_collectors'),
'profile_params': request.session.get('profile_params'),
'show_effect': bool(request.env['ir.config_parameter'].sudo().get_param('base_setup.show_effect')),
'currencies': self.env['res.currency'].get_all_currencies(),
'quick_login': str2bool(request.env['ir.config_parameter'].sudo().get_param('web.quick_login', default=True), True),
'bundle_params': {
'lang': request.session.context['lang'],
},
'test_mode': config['test_enable'],
}
if request.session.debug:
session_info['bundle_params']['debug'] = request.session.debug
@ -173,7 +200,6 @@ class Http(models.AbstractModel):
})
return session_info
@api.deprecated("Deprecated since 19.0, use get_all_currencies on 'res.currency'")
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}
return self.env['res.currency'].get_all_currencies()