diff --git a/addons/hw_proxy/controllers/main.py b/addons/hw_proxy/controllers/main.py index a6c93e2939d..33e20f8a76a 100644 --- a/addons/hw_proxy/controllers/main.py +++ b/addons/hw_proxy/controllers/main.py @@ -101,7 +101,7 @@ class Proxy(http.Controller):

The list of connected USB devices as seen by the IoTBox

""" if debug is None: - resp += """(debug version)""" + resp += """(debug version)""" devices = subprocess.check_output("lsusb").decode('utf-8').split('\n') count = 0 resp += "
\n" diff --git a/addons/point_of_sale/controllers/main.py b/addons/point_of_sale/controllers/main.py index 79ec844fdf8..0fca1369384 100644 --- a/addons/point_of_sale/controllers/main.py +++ b/addons/point_of_sale/controllers/main.py @@ -12,7 +12,7 @@ _logger = logging.getLogger(__name__) class PosController(http.Controller): @http.route('/pos/web', type='http', auth='user') - def pos_web(self, debug=False, **k): + def pos_web(self, **k): # if user not logged in, log him in pos_sessions = request.env['pos.session'].search([ ('state', '=', 'opened'), diff --git a/addons/point_of_sale/views/pos_templates.xml b/addons/point_of_sale/views/pos_templates.xml index dfadf1af349..cb1a8a81a01 100644 --- a/addons/point_of_sale/views/pos_templates.xml +++ b/addons/point_of_sale/views/pos_templates.xml @@ -31,12 +31,14 @@ var odoo = { csrf_token: "", session_info: , + debug: "", }; + @@ -422,6 +431,7 @@ + @@ -840,6 +850,7 @@ + diff --git a/addons/web_settings_dashboard/controllers/main.py b/addons/web_settings_dashboard/controllers/main.py index 574f9e8fd21..fb1105ba939 100644 --- a/addons/web_settings_dashboard/controllers/main.py +++ b/addons/web_settings_dashboard/controllers/main.py @@ -73,7 +73,7 @@ class WebSettingsDashboard(http.Controller): 'share': { 'server_version': release.version, 'expiration_date': expiration_date, - 'debug': request.debug, + 'debug': request.session.debug, 'demo_active': demo_active, }, 'company': { diff --git a/addons/web_settings_dashboard/static/src/xml/dashboard.xml b/addons/web_settings_dashboard/static/src/xml/dashboard.xml index b8c8f339ebd..5e55e8d7a87 100644 --- a/addons/web_settings_dashboard/static/src/xml/dashboard.xml +++ b/addons/web_settings_dashboard/static/src/xml/dashboard.xml @@ -123,13 +123,13 @@

- Activate the developer mode -
- Activate the developer mode (with assets) -
- Deactivate the developer mode -
- Load demo data +
+ Activate the developer mode + Activate the developer mode (with assets) + Activate the developer mode (with tests assets) + Deactivate the developer mode + Load demo data +
diff --git a/addons/website/models/ir_qweb.py b/addons/website/models/ir_qweb.py index ea33aa114b2..664838afe77 100644 --- a/addons/website/models/ir_qweb.py +++ b/addons/website/models/ir_qweb.py @@ -44,7 +44,7 @@ class QWeb(models.AbstractModel): atts = super(QWeb, self)._post_processing_att(tagName, atts, options) if options.get('inherit_branding') or options.get('rendering_bundle') or \ - options.get('edit_translations') or options.get('debug') or (request and request.debug): + options.get('edit_translations') or options.get('debug') or (request and request.session.debug): return atts website = request and getattr(request, 'website', None) diff --git a/addons/website/tests/test_qweb.py b/addons/website/tests/test_qweb.py index e3070d9f009..5ca9344aa32 100644 --- a/addons/website/tests/test_qweb.py +++ b/addons/website/tests/test_qweb.py @@ -93,7 +93,10 @@ class MockRequest(object): if not routing: app.match = werkzeugRaiseNotFound self.request = MockObject( - env=env, context=context or {}, db=None, debug=False, + env=env, context=context or {}, db=None, + session=MockObject( + debug=False + ), website=website, httprequest=MockObject( path='/hello/', app=app diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index c6f112d554d..3c5904dd034 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -904,7 +904,7 @@

:

- + @@ -969,7 +969,7 @@
  • Contact Us
  • - + @@ -996,7 +996,7 @@ - + @@ -1123,7 +1123,7 @@ - + diff --git a/odoo/addons/base/models/assetsbundle.py b/odoo/addons/base/models/assetsbundle.py index faf8a3cb8fd..04e85944c0e 100644 --- a/odoo/addons/base/models/assetsbundle.py +++ b/odoo/addons/base/models/assetsbundle.py @@ -135,7 +135,7 @@ class AssetsBundle(object): :returns [(tagName, attributes, content)] if the tag is auto close """ response = [] - if debug == 'assets': + if debug and 'assets' in debug: if css and self.stylesheets: is_css_preprocessed, old_attachments = self.is_css_preprocessed() if not is_css_preprocessed: diff --git a/odoo/addons/base/models/ir_http.py b/odoo/addons/base/models/ir_http.py index 420ba00026f..ac6ccbc9eac 100644 --- a/odoo/addons/base/models/ir_http.py +++ b/odoo/addons/base/models/ir_http.py @@ -24,6 +24,9 @@ from odoo.tools import pycompat, consteq from odoo.tools.mimetypes import guess_mimetype from odoo.modules.module import get_resource_path, get_module_path +from odoo.http import ALLOWED_DEBUG_MODES +from odoo.tools.misc import str2bool + _logger = logging.getLogger(__name__) @@ -125,6 +128,21 @@ class IrHttp(models.AbstractModel): raise AccessDenied() return auth_method + @classmethod + def _handle_debug(cls): + # Store URL debug mode (might be empty) into session + if 'debug' in request.httprequest.args: + debug_mode = [] + for debug in request.httprequest.args['debug'].split(','): + if debug not in ALLOWED_DEBUG_MODES: + debug = '1' if str2bool(debug, debug) else '' + debug_mode.append(debug) + debug_mode = ','.join(debug_mode) + + # Write on session only when needed + if debug_mode != request.session.debug: + request.session.debug = debug_mode + @classmethod def _serve_attachment(cls): env = api.Environment(request.cr, SUPERUSER_ID, request.context) @@ -162,6 +180,9 @@ class IrHttp(models.AbstractModel): @classmethod def _handle_exception(cls, exception): + # in case of Exception, e.g. 404, we don't step into _dispatch + cls._handle_debug() + # If handle_exception returns something different than None, it will be used as a response # This is done first as the attachment path may @@ -182,6 +203,8 @@ class IrHttp(models.AbstractModel): @classmethod def _dispatch(cls): + cls._handle_debug() + # locate the controller method try: rule, arguments = cls._find_handler(return_rule=True) diff --git a/odoo/addons/base/models/ir_ui_menu.py b/odoo/addons/base/models/ir_ui_menu.py index 7459dd29504..d726ee2cfa1 100644 --- a/odoo/addons/base/models/ir_ui_menu.py +++ b/odoo/addons/base/models/ir_ui_menu.py @@ -122,7 +122,7 @@ class IrUiMenu(models.Model): the menu hierarchy of the current user. Uses a cache for speeding up the computation. """ - visible_ids = self._visible_menu_ids(request.debug if request else False) + visible_ids = self._visible_menu_ids(request.session.debug if request else False) return self.filtered(lambda menu: menu.id in visible_ids) @api.model diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py index 8c5f4809f32..30600ee6bf7 100644 --- a/odoo/addons/base/models/ir_ui_view.py +++ b/odoo/addons/base/models/ir_ui_view.py @@ -1356,7 +1356,7 @@ actual arch. res_company=self.env.company.sudo(), keep_query=keep_query, request=request, # might be unbound if we're not in an httprequest context - debug=request.debug if request else False, + debug=request.session.debug if request else '', json=json, quote_plus=werkzeug.url_quote_plus, time=time, diff --git a/odoo/http.py b/odoo/http.py index 67243cf5a52..3f4dd6fad27 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -64,6 +64,21 @@ STATIC_CACHE = 60 * 60 * 24 * 7 # To remove when corrected in Babel babel.core.LOCALE_ALIASES['nb'] = 'nb_NO' +""" Debug mode is stored in session and should always be a string. + It can be activated with an URL query string `debug=` 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'] + #---------------------------------------------------------- # RequestHandler #---------------------------------------------------------- @@ -143,15 +158,10 @@ def dispatch_rpc(service_name, method, params): odoo.tools.debugger.post_mortem(odoo.tools.config, sys.exc_info()) raise -def local_redirect(path, query=None, keep_hash=False, forward_debug=True, code=303): +def local_redirect(path, query=None, keep_hash=False, code=303): url = path if not query: query = {} - if request and request.debug: - if forward_debug: - query['debug'] = '' - else: - query['debug'] = None if query: url += '?' + werkzeug.url_encode(query) if keep_hash: @@ -345,22 +355,6 @@ class WebRequest(object): return checked_call(self.db, *args, **kwargs) return self.endpoint(*args, **kwargs) - @property - def debug(self): - """ Indicates whether the current request is in "debug" mode - """ - debug = 'debug' in self.httprequest.args - if debug and self.httprequest.args.get('debug') == 'assets': - debug = 'assets' - - # check if request from rpc in debug mode - if not debug: - debug = self.httprequest.environ.get('HTTP_X_DEBUG_MODE') - - if not debug and self.httprequest.referrer: - debug = 'debug' in urls.url_parse(self.httprequest.referrer).decode_query() - return debug - @contextlib.contextmanager def registry_cr(self): warnings.warn('please use request.registry and request.cr directly', DeprecationWarning) @@ -763,7 +757,7 @@ class HttpRequest(WebRequest): if request.httprequest.method == 'OPTIONS' and request.endpoint and request.endpoint.routing.get('cors'): headers = { 'Access-Control-Max-Age': 60 * 60 * 24, - 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, X-Debug-Mode' + 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept' } return Response(status=200, headers=headers) @@ -1038,7 +1032,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session): def logout(self, keep_db=False): for k in list(self): - if not (keep_db and k == 'db'): + if not (keep_db and k == 'db') and k != 'debug': del self[k] self._default_values() self.rotate = True @@ -1049,6 +1043,9 @@ class OpenERPSession(werkzeug.contrib.sessions.Session): self.setdefault("login", None) self.setdefault("session_token", None) self.setdefault("context", {}) + # Force tests debug mode when test mode enabled to load 'assets_tests' + test_mode = odoo.tools.config['test_enable'] or odoo.tools.config['test_file'] + self.setdefault("debug", 'tests' if test_mode else '') def get_context(self): """ @@ -1242,13 +1239,12 @@ class Response(werkzeug.wrappers.Response): class DisableCacheMiddleware(object): def __init__(self, app): self.app = app + def __call__(self, environ, start_response): def start_wrapped(status, headers): - referer = environ.get('HTTP_REFERER', '') - parsed = urls.url_parse(referer) - debug = parsed.query.count('debug') >= 1 - - if debug: + req = werkzeug.wrappers.Request(environ) + root.setup_session(req) + if req.session and req.session.debug: new_headers = [('Cache-Control', 'no-cache')] for k, v in headers: diff --git a/odoo/models.py b/odoo/models.py index a2499c6a68d..77701cf676a 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -1237,7 +1237,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): for group_ext_id in not_has_groups: if group_ext_id == 'base.group_no_one': # check: the group_no_one is effective in debug mode only - if user.has_group(group_ext_id) and request and request.debug: + if user.has_group(group_ext_id) and request and request.session.debug: return False else: if user.has_group(group_ext_id): @@ -1246,7 +1246,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): for group_ext_id in has_groups: if group_ext_id == 'base.group_no_one': # check: the group_no_one is effective in debug mode only - if user.has_group(group_ext_id) and request and request.debug: + if user.has_group(group_ext_id) and request and request.session.debug: return True else: if user.has_group(group_ext_id):