[IMP] base, web, *: make KarmaError an except_orm

* = gamification, test_website, stock

- KarmaError is now handled as a 400 exception.
- test_website has been updated.
- NO_POSTMORTEM is now clean it was referencing duplicates as most the
  exceptions inherit from except_orm.
- serialize_exception from http.py has been moved to ir_http
  to take advantage of the odoo inheritance system. We can then
  extend ir_http serialize_exception method to add the KarmaError
  logic if and only if gamification is installed.
  Places where serialize_exception was previously used are updated.

Part of https://github.com/odoo/odoo/pull/32132
task-1894820
This commit is contained in:
fja-odoo
2019-06-28 08:53:53 +00:00
parent 90818fd083
commit 0d1407a715
9 changed files with 90 additions and 44 deletions
@@ -1,15 +1,24 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from werkzeug.exceptions import Forbidden
from odoo import api, tools, fields, models
from odoo import api, tools, fields, models, exceptions, http
from odoo.tools.translate import html_translate
class KarmaError(Forbidden):
class KarmaError(exceptions.except_orm):
""" Karma-related error, used for forum and posts. """
pass
def __init__(self, msg):
super(KarmaError, self).__init__(msg)
class Http(models.AbstractModel):
_inherit = 'ir.http'
@classmethod
def serialize_exception(self, e):
res = super(Http, self).serialize_exception(e)
if isinstance(e, KarmaError):
res["exception_type"] = "karma_error"
return res
class KarmaRank(models.Model):
+1 -2
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from odoo import http
from odoo.http import request
from odoo.addons.web.controllers.main import _serialize_exception
from odoo.tools import html_escape
import json
@@ -37,7 +36,7 @@ class StockReportController(http.Controller):
response.set_cookie('fileToken', token)
return response
except Exception as e:
se = _serialize_exception(e)
se = request.env['ir.http'].serialize_exception(e)
error = {
'code': 200,
'message': 'Odoo Server Error',
+1
View File
@@ -14,6 +14,7 @@ dependencies. Neither we want to add in website module some routes, views and
models which only purpose is to run tests.""",
'depends': [
'website',
'gamification',
],
'data': [
'views/templates.xml',
+9
View File
@@ -8,6 +8,7 @@ from odoo import http
from odoo.http import request
from odoo.addons.portal.controllers.web import Home
from odoo.exceptions import UserError, ValidationError, AccessError, MissingError, AccessError, AccessDenied
from odoo.addons.gamification.models.gamification_karma_rank import KarmaError
class WebsiteTest(Home):
@@ -80,6 +81,14 @@ class WebsiteTest(Home):
def test_missing_error_http(self, **kwargs):
raise MissingError("This is a missing http test")
@http.route('/test_karma_error_json', type='json', auth='public', website=True)
def test_karma_error_rpc(self, **kwargs):
raise KarmaError("This is a karma rpc test")
@http.route('/test_karma_error_http', type='http', auth='public', website=True)
def test_karma_error_http(self, **kwargs):
raise KarmaError("This is a karma http test")
@http.route('/test_internal_error_json', type='json', auth='public', website=True)
def test_internal_error_json(self, **kwargs):
raise werkzeug.exceptions.InternalServerError()
@@ -44,6 +44,13 @@ tour.register('test_error_website', {
content: "rpc error 403 modal has message",
extra_trigger: 'div.o_dialog_warning.modal-body:contains("This is an access denied rpc test")',
trigger: 'button.btn.btn-primary',
}, {
content: "trigger rpc missing error",
trigger: 'a[href="/test_karma_error_json"]',
}, {
content: "rpc missing error modal has message",
extra_trigger: 'div.o_dialog_warning.modal-body:contains("This is a karma rpc test")',
trigger: 'button.btn.btn-primary',
}, {
content: "trigger rpc error 500",
trigger: 'a[href="/test_internal_error_json"]',
@@ -131,6 +138,24 @@ tour.register('test_error_website', {
run: function () {
window.location.href = window.location.origin + '/test_karma_error_http?debug=0';
},
}, {
content: "http karma error page has title and message",
extra_trigger: 'h1:contains("Oops! Something went wrong.")',
trigger: 'div.container pre:contains("This is a karma http test")',
run: function () {
window.location.href = window.location.origin + '/test_karma_error_http?debug=1';
},
}, {
content: "http karma error page debug has title and message open",
extra_trigger: 'h1:contains("Oops! Something went wrong.")',
trigger: 'div#error_main.collapse.show pre:contains("This is a karma http test")',
run: function () {},
}, {
content: "http karma error page debug has traceback closed",
trigger: 'body:has(div#error_traceback.collapse:not(.show) pre#exception_traceback)',
run: function () {
window.location.href = window.location.origin + '/test_access_denied_http?debug=0';
},
}, {
content: "http error 403 page has title but no message",
extra_trigger: 'h1:contains("403: Forbidden")',
+3 -4
View File
@@ -42,8 +42,7 @@ from odoo.tools.translate import _
from odoo.tools.misc import str2bool, xlwt, file_open
from odoo.tools.safe_eval import safe_eval
from odoo import http, tools
from odoo.http import content_disposition, dispatch_rpc, request, \
serialize_exception as _serialize_exception, Response
from odoo.http import content_disposition, dispatch_rpc, request, Response
from odoo.exceptions import AccessError, UserError, AccessDenied
from odoo.models import check_method_name
from odoo.service import db, security
@@ -83,7 +82,7 @@ def serialize_exception(f):
return f(*args, **kwargs)
except Exception as e:
_logger.exception("An exception occured during an http request")
se = _serialize_exception(e)
se = request.registry['ir.http'].serialize_exception(e)
error = {
'code': 200,
'message': "Odoo Server Error",
@@ -1694,7 +1693,7 @@ class ReportController(http.Controller):
else:
return
except Exception as e:
se = _serialize_exception(e)
se = request.env['ir.http'].serialize_exception(e)
error = {
'code': 200,
'message': "Odoo Server Error",
@@ -17,6 +17,7 @@ var map_title ={
validation_error: _lt("Validation Error"),
except_orm: _lt("Global Business Error"),
access_denied: _lt("Access Denied"),
karma_error: _lt("Karma Error"),
};
/**
+29 -1
View File
@@ -9,6 +9,7 @@ import mimetypes
import os
import re
import sys
import traceback
import werkzeug
import werkzeug.exceptions
@@ -20,7 +21,7 @@ import odoo
from odoo import api, http, models, tools, SUPERUSER_ID
from odoo.exceptions import AccessDenied, AccessError
from odoo.http import request, STATIC_CACHE, content_disposition
from odoo.tools import pycompat, consteq
from odoo.tools import consteq, pycompat, ustr
from odoo.tools.mimetypes import guess_mimetype
from odoo.modules.module import get_resource_path, get_module_path
@@ -178,6 +179,33 @@ class IrHttp(models.AbstractModel):
return attach
return False
@classmethod
def serialize_exception(self, e):
tmp = {
"name": type(e).__module__ + "." + type(e).__name__ if type(e).__module__ else type(e).__name__,
"debug": traceback.format_exc(),
"message": ustr(e),
"arguments": e.args,
"exception_type": "internal_error"
}
if isinstance(e, odoo.exceptions.UserError):
tmp["exception_type"] = "user_error"
elif isinstance(e, odoo.exceptions.Warning):
tmp["exception_type"] = "warning"
elif isinstance(e, odoo.exceptions.RedirectWarning):
tmp["exception_type"] = "warning"
elif isinstance(e, odoo.exceptions.AccessError):
tmp["exception_type"] = "access_error"
elif isinstance(e, odoo.exceptions.MissingError):
tmp["exception_type"] = "missing_error"
elif isinstance(e, odoo.exceptions.AccessDenied):
tmp["exception_type"] = "access_denied"
elif isinstance(e, odoo.exceptions.ValidationError):
tmp["exception_type"] = "validation_error"
elif isinstance(e, odoo.exceptions.except_orm):
tmp["exception_type"] = "except_orm"
return tmp
@classmethod
def _handle_exception(cls, exception):
# in case of Exception, e.g. 404, we don't step into _dispatch
+6 -31
View File
@@ -98,16 +98,16 @@ def replace_request_password(args):
args[2] = '*'
return tuple(args)
# don't trigger debugger for those exceptions, they carry user-facing warnings
# and indications, they're not necessarily indicative of anything being
# *broken*
NO_POSTMORTEM = (odoo.osv.orm.except_orm,
odoo.exceptions.AccessError,
odoo.exceptions.ValidationError,
odoo.exceptions.MissingError,
NO_POSTMORTEM = (odoo.exceptions.except_orm,
odoo.exceptions.AccessDenied,
odoo.exceptions.Warning,
odoo.exceptions.RedirectWarning)
def dispatch_rpc(service_name, method, params):
""" Handle a RPC call.
@@ -316,7 +316,7 @@ class WebRequest(object):
"""Called within an except block to allow converting exceptions
to abitrary responses. Anything returned (except None) will
be used as response."""
self._failed = exception # prevent tx commit
self._failed = exception # prevent tx commit
if not isinstance(exception, NO_POSTMORTEM) \
and not isinstance(exception, werkzeug.exceptions.HTTPException):
odoo.tools.debugger.post_mortem(
@@ -641,7 +641,7 @@ class JsonRequest(WebRequest):
error = {
'code': 200,
'message': "Odoo Server Error",
'data': serialize_exception(exception),
'data': request.registry['ir.http'].serialize_exception(exception),
}
if isinstance(exception, werkzeug.exceptions.NotFound):
error['http_status'] = 404
@@ -691,31 +691,6 @@ class JsonRequest(WebRequest):
except Exception as e:
return self._handle_exception(e)
def serialize_exception(e):
tmp = {
"name": type(e).__module__ + "." + type(e).__name__ if type(e).__module__ else type(e).__name__,
"debug": traceback.format_exc(),
"message": ustr(e),
"arguments": e.args,
"exception_type": "internal_error"
}
if isinstance(e, odoo.exceptions.UserError):
tmp["exception_type"] = "user_error"
elif isinstance(e, odoo.exceptions.Warning):
tmp["exception_type"] = "warning"
elif isinstance(e, odoo.exceptions.RedirectWarning):
tmp["exception_type"] = "warning"
elif isinstance(e, odoo.exceptions.AccessError):
tmp["exception_type"] = "access_error"
elif isinstance(e, odoo.exceptions.MissingError):
tmp["exception_type"] = "missing_error"
elif isinstance(e, odoo.exceptions.AccessDenied):
tmp["exception_type"] = "access_denied"
elif isinstance(e, odoo.exceptions.ValidationError):
tmp["exception_type"] = "validation_error"
elif isinstance(e, odoo.exceptions.except_orm):
tmp["exception_type"] = "except_orm"
return tmp
class HttpRequest(WebRequest):
""" Handler for the ``http`` request type.