[IMP] http_routing, *: move error pages to http_routing

* = portal, website, test_website, account, sms

Portal an Survey error pages were ugly default pages.
Now the error pages will be the same as the website ones.

Also fixing single module builds tests

task-2059969

closes odoo/odoo#35535

Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
This commit is contained in:
fja-odoo
2019-10-02 06:59:15 +00:00
parent 92db71ccc4
commit 423402f1e5
10 changed files with 405 additions and 358 deletions
@@ -10,7 +10,7 @@ from odoo.tools import mute_logger
@tests.tagged('post_install', '-at_install') @tests.tagged('post_install', '-at_install')
class TestUi(tests.HttpCase): class TestUi(tests.HttpCase):
@mute_logger('odoo.addons.website.models.ir_http', 'odoo.http') @mute_logger('odoo.addons.http_routing.models.ir_http', 'odoo.http')
def test_01_portal_attachment(self): def test_01_portal_attachment(self):
"""Test the portal chatter attachment route.""" """Test the portal chatter attachment route."""
+1
View File
@@ -11,6 +11,7 @@ Proposes advanced routing options not available in web or base to keep
base modules simple. base modules simple.
""", """,
'data': [ 'data': [
'views/http_routing_template.xml',
'views/res_lang_views.xml', 'views/res_lang_views.xml',
], ],
'depends': ['web'], 'depends': ['web'],
+87 -1
View File
@@ -5,6 +5,7 @@ import json
import logging import logging
import os import os
import re import re
import traceback
import unicodedata import unicodedata
import werkzeug import werkzeug
@@ -15,8 +16,9 @@ except ImportError:
slugify_lib = None slugify_lib = None
import odoo import odoo
from odoo import api, models from odoo import api, models, registry, exceptions
from odoo.addons.base.models.ir_http import RequestUID, ModelConverter from odoo.addons.base.models.ir_http import RequestUID, ModelConverter
from odoo.addons.base.models.qweb import QWebException
from odoo.http import request from odoo.http import request
from odoo.osv import expression from odoo.osv import expression
from odoo.tools import config, ustr, pycompat from odoo.tools import config, ustr, pycompat
@@ -540,3 +542,87 @@ class IrHttp(models.AbstractModel):
if request.httprequest.query_string: if request.httprequest.query_string:
path += '?' + request.httprequest.query_string.decode('utf-8') path += '?' + request.httprequest.query_string.decode('utf-8')
return werkzeug.utils.redirect(path, code=301) return werkzeug.utils.redirect(path, code=301)
@classmethod
def _get_exception_code_values(cls, exception):
""" Return a tuple with the error code following by the values matching the exception"""
code = 500 # default code
values = dict(
exception=exception,
traceback=traceback.format_exc(),
)
# only except_orm exceptions contain a message
if isinstance(exception, exceptions.except_orm):
values['error_message'] = exception.name
code = 400
if isinstance(exception, exceptions.AccessError):
code = 403
elif isinstance(exception, QWebException):
values.update(qweb_exception=exception)
if type(exception.error) == exceptions.AccessError:
code = 403
elif isinstance(exception, werkzeug.exceptions.HTTPException):
code = exception.code
values.update(
status_message=werkzeug.http.HTTP_STATUS_CODES[code],
status_code=code,
)
return (code, values)
@classmethod
def _get_values_500_error(cls, env, values, exception):
values['view'] = env["ir.ui.view"]
return values
@classmethod
def _get_error_html(cls, env, code, values):
return env['ir.ui.view'].render_template('http_routing.%s' % code, values)
@classmethod
def _handle_exception(cls, exception):
is_frontend_request = bool(getattr(request, 'is_frontend', False))
if not is_frontend_request:
# Don't touch non frontend requests exception handling
return super(IrHttp, cls)._handle_exception(exception)
try:
response = super(IrHttp, cls)._handle_exception(exception)
if isinstance(response, Exception):
exception = response
else:
# if parent excplicitely returns a plain response, then we don't touch it
return response
except Exception as e:
if 'werkzeug' in config['dev_mode']:
raise e
exception = e
code, values = cls._get_exception_code_values(exception)
if code is None:
# Hand-crafted HTTPException likely coming from abort(),
# usually for a redirect response -> return it directly
return exception
if not request.uid:
cls._auth_method_public()
with registry(request.env.cr.dbname).cursor() as cr:
env = api.Environment(cr, request.uid, request.env.context)
if code == 500:
_logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
values = cls._get_values_500_error(env, values, exception)
elif code == 403:
_logger.warn("403 Forbidden:\n\n%s", values['traceback'])
elif code == 400:
_logger.warn("400 Bad Request:\n\n%s", values['traceback'])
try:
html = cls._get_error_html(env, code, values)
except Exception:
html = env['ir.ui.view'].render_template('http_routing.http_error', values)
return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="http_error">
<t t-call="web.frontend_layout">
<div id="wrap">
<div class="oe_structure">
<h1 class="container mt32"><t t-esc="status_code"/>: <t t-esc="status_message"/></h1>
</div>
<t t-if="editable or debug">
<t t-call="http_routing.http_error_debug"/>
</t>
</div>
</t>
</template>
<template id="error_message">
<p t-if="error_message">
<strong>Error message:</strong>
<pre t-esc="error_message"/>
</p>
</template>
<template id="http_error_debug">
<div class="container accordion mb32 mt32" id="debug_infos">
<div class="card" t-if="error_message">
<h4 class="card-header">
<a data-toggle="collapse" href="#error_main">Error</a>
</h4>
<div id="error_main" class="collapse show">
<div class="card-body">
<t t-call="http_routing.error_message"/>
</div>
</div>
</div>
<div class="card" t-if="qweb_exception">
<h4 class="card-header">
<a data-toggle="collapse" href="#error_qweb">QWeb</a>
</h4>
<div id="error_qweb" class="collapse show">
<div class="card-body">
<p t-if="exception.message">
<strong>Error message:</strong>
<pre t-esc="exception.message"/>
</p>
<p>
The error occured while rendering the template <code t-esc="qweb_exception.name"/>
<t t-if="qweb_exception.html">and evaluating the following expression: <code t-esc="qweb_exception.html"/></t>
</p>
</div>
</div>
</div>
<div class="card" t-if="traceback">
<h4 class="card-header">
<a data-toggle="collapse" href="#error_traceback">Traceback</a>
</h4>
<div id="error_traceback" t-attf-class="collapse #{not error_message and not qweb_exception and 'show'}">
<div class="card-body">
<pre id="exception_traceback" t-esc="traceback"/>
</div>
</div>
</div>
</div>
</template>
<template id="400">
<t t-call="web.frontend_layout">
<div id="wrap">
<div class="container">
<h1 class="mt-5">Oops! Something went wrong.</h1>
<p>Take a look at the error message below.</p>
</div>
<t t-if="editable or request.session.debug">
<t t-call="http_routing.http_error_debug"/>
</t>
<t t-else="">
<div class="container">
<t t-call="http_routing.error_message"/>
</div>
</t>
</div>
</t>
</template>
<template id="403">
<t t-call="web.frontend_layout">
<div id="wrap">
<div class="container">
<h1 class="mt-5">403: Forbidden</h1>
<p>The page you were looking for could not be authorized.</p>
</div>
<t t-if="editable or request.session.debug">
<t t-call="http_routing.http_error_debug"/>
</t>
<t t-else="">
<div class="container">
<t t-call="http_routing.error_message"/>
</div>
</t>
</div>
</t>
</template>
<template id="404">
<t t-call="web.frontend_layout">
<div id="wrap">
<t t-raw="0"/>
<div class="oe_structure oe_empty">
<div class="container">
<h1 class="mt-5">404: Page not found!</h1>
<p>
The page you were looking for could not be found; it is possible you have
typed the address incorrectly, but it has most probably been removed due
to the recent reorganisation.
</p>
</div>
</div>
</div>
</t>
</template>
<template id="500">
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- This template should not use any variable except those provided by http_routing.ir_http._handle_exception -->
<!-- no request.crsf_token, no theme style, no assets, ... cursor can be broken during rendering ! -->
<!-- see test_05_reset_specific_view_controller_broken_request -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<html>
<head>
<title t-esc="status_message">Internal Server Error</title>
<t t-set="debug" t-value="True"/>
<link rel="stylesheet" href="/web/static/lib/bootstrap/css/bootstrap.css"/>
<script src="/web/static/lib/jquery/jquery.js" type="text/javascript"/>
<script type="text/javascript" src="/web/static/lib/bootstrap/js/util.js"/>
<script type="text/javascript" src="/web/static/lib/bootstrap/js/collapse.js"/>
<style>
html {
font-size: 14px;
}
</style>
</head>
<body>
<div id="wrapwrap">
<header>
<div class="navbar navbar-expand-md navbar-light bg-light">
<div class="container">
<div class="collapse navbar-collapse navbar-top-collapse">
<ul class="navbar-nav ml-auto" id="top_menu">
<li class="nav-item"><a href="/" class="nav-link">Home</a></li>
<li class="nav-item"><a href="javascript: window.history.back()" class="nav-link">Back</a></li>
</ul>
</div>
</div>
</div>
</header>
<main>
<div id="error_message" class="oe_structure">
<h2 class="container mt32"><t t-esc="status_code"/>: <t t-esc="status_message"/></h2>
</div>
<t t-if="editable or debug">
<t t-call="http_routing.http_error_debug"/>
</t>
</main>
</div>
</body>
</html>
</template>
</odoo>
+9
View File
@@ -493,4 +493,13 @@
</body> </body>
</t> </t>
</template> </template>
<template id="portal_404" inherit_id="http_routing.404">
<xpath expr="//p" position="after">
<p>Maybe you were looking for one of these popular pages ?</p>
<ul>
<li><a href="/my">Documents</a></li>
</ul>
</xpath>
</template>
</odoo> </odoo>
+1 -1
View File
@@ -16,7 +16,7 @@
<template id="qunit_suite" name="sms_widget_tests" inherit_id="web.qunit_suite"> <template id="qunit_suite" name="sms_widget_tests" inherit_id="web.qunit_suite">
<xpath expr="." position="inside"> <xpath expr="." position="inside">
<script type="text/javascript" src="/sms/static/src/tests/sms_widget_test.js"></script> <script type="text/javascript" src="/sms/static/tests/sms_widget_test.js"></script>
</xpath> </xpath>
</template> </template>
</data> </data>
+1 -1
View File
@@ -5,6 +5,6 @@ from odoo.tools import mute_logger
@odoo.tests.common.tagged('post_install', '-at_install') @odoo.tests.common.tagged('post_install', '-at_install')
class TestWebsiteError(odoo.tests.HttpCase): class TestWebsiteError(odoo.tests.HttpCase):
@mute_logger('odoo.addons.website.models.ir_http', 'odoo.http') @mute_logger('odoo.addons.http_routing.models.ir_http', 'odoo.http')
def test_01_run_test(self): def test_01_run_test(self):
self.start_tour("/test_error_view", 'test_error_website') self.start_tour("/test_error_view", 'test_error_website')
@@ -31,7 +31,7 @@ class TestWebsiteResetViews(odoo.tests.HttpCase):
self.View = self.env['ir.ui.view'] self.View = self.env['ir.ui.view']
self.test_view = self.Website.viewref('test_website.test_view') self.test_view = self.Website.viewref('test_website.test_view')
@mute_logger('odoo.addons.website.models.ir_http') @mute_logger('odoo.addons.http_routing.models.ir_http')
def test_01_reset_specific_page_view(self): def test_01_reset_specific_page_view(self):
self.test_page_view = self.Website.viewref('test_website.test_page_view') self.test_page_view = self.Website.viewref('test_website.test_page_view')
total_views = self.View.search_count([('type', '=', 'qweb')]) total_views = self.View.search_count([('type', '=', 'qweb')])
@@ -40,7 +40,7 @@ class TestWebsiteResetViews(odoo.tests.HttpCase):
self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view") self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view")
self.fix_it('/test_page_view') self.fix_it('/test_page_view')
@mute_logger('odoo.addons.website.models.ir_http') @mute_logger('odoo.addons.http_routing.models.ir_http')
def test_02_reset_specific_view_controller(self): def test_02_reset_specific_view_controller(self):
total_views = self.View.search_count([('type', '=', 'qweb')]) total_views = self.View.search_count([('type', '=', 'qweb')])
# Trigger COW then break the QWEB XML on it # Trigger COW then break the QWEB XML on it
@@ -49,7 +49,7 @@ class TestWebsiteResetViews(odoo.tests.HttpCase):
self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view") self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view")
self.fix_it('/test_view') self.fix_it('/test_view')
@mute_logger('odoo.addons.website.models.ir_http') @mute_logger('odoo.addons.http_routing.models.ir_http')
def test_03_reset_specific_view_controller_t_called(self): def test_03_reset_specific_view_controller_t_called(self):
self.test_view_to_be_t_called = self.Website.viewref('test_website.test_view_to_be_t_called') self.test_view_to_be_t_called = self.Website.viewref('test_website.test_view_to_be_t_called')
@@ -60,7 +60,7 @@ class TestWebsiteResetViews(odoo.tests.HttpCase):
self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view") self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view")
self.fix_it('/test_view') self.fix_it('/test_view')
@mute_logger('odoo.addons.website.models.ir_http') @mute_logger('odoo.addons.http_routing.models.ir_http')
def test_04_reset_specific_view_controller_inherit(self): def test_04_reset_specific_view_controller_inherit(self):
self.test_view_child_broken = self.Website.viewref('test_website.test_view_child_broken') self.test_view_child_broken = self.Website.viewref('test_website.test_view_child_broken')
@@ -71,7 +71,7 @@ class TestWebsiteResetViews(odoo.tests.HttpCase):
self.fix_it('/test_view') self.fix_it('/test_view')
# This test work in real life, but not in test mode since we cannot rollback savepoint. # This test work in real life, but not in test mode since we cannot rollback savepoint.
# @mute_logger('odoo.addons.website.models.ir_http', 'odoo.addons.website.models.ir_ui_view') # @mute_logger('odoo.addons.http_routing.models.ir_http', 'odoo.addons.website.models.ir_ui_view')
# def test_05_reset_specific_view_controller_broken_request(self): # def test_05_reset_specific_view_controller_broken_request(self):
# total_views = self.View.search_count([('type', '=', 'qweb')]) # total_views = self.View.search_count([('type', '=', 'qweb')])
# # Trigger COW then break the QWEB XML on it # # Trigger COW then break the QWEB XML on it
@@ -80,7 +80,7 @@ class TestWebsiteResetViews(odoo.tests.HttpCase):
# self.fix_it('/test_view') # self.fix_it('/test_view')
# also mute ir.ui.view as `get_view_id()` will raise "Could not find view object with xml_id 'not.exist'"" # also mute ir.ui.view as `get_view_id()` will raise "Could not find view object with xml_id 'not.exist'""
@mute_logger('odoo.addons.website.models.ir_http', 'odoo.addons.website.models.ir_ui_view') @mute_logger('odoo.addons.http_routing.models.ir_http', 'odoo.addons.website.models.ir_ui_view')
def test_06_reset_specific_view_controller_inexisting_template(self): def test_06_reset_specific_view_controller_inexisting_template(self):
total_views = self.View.search_count([('type', '=', 'qweb')]) total_views = self.View.search_count([('type', '=', 'qweb')])
# Trigger COW then break the QWEB XML on it # Trigger COW then break the QWEB XML on it
@@ -88,14 +88,14 @@ class TestWebsiteResetViews(odoo.tests.HttpCase):
self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view (2)") self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view (2)")
self.fix_it('/test_view') self.fix_it('/test_view')
@mute_logger('odoo.addons.website.models.ir_http') @mute_logger('odoo.addons.http_routing.models.ir_http')
def test_07_reset_page_view_complete_flow(self): def test_07_reset_page_view_complete_flow(self):
self.start_tour("/", 'test_reset_page_view_complete_flow_part1', login="admin") self.start_tour("/", 'test_reset_page_view_complete_flow_part1', login="admin")
self.fix_it('/test_page_view') self.fix_it('/test_page_view')
self.start_tour("/", 'test_reset_page_view_complete_flow_part2', login="admin") self.start_tour("/", 'test_reset_page_view_complete_flow_part2', login="admin")
self.fix_it('/test_page_view') self.fix_it('/test_page_view')
@mute_logger('odoo.addons.website.models.ir_http') @mute_logger('odoo.addons.http_routing.models.ir_http')
def test_08_reset_specific_page_view_hard_mode(self): def test_08_reset_specific_page_view_hard_mode(self):
self.test_page_view = self.Website.viewref('test_website.test_page_view') self.test_page_view = self.Website.viewref('test_website.test_page_view')
total_views = self.View.search_count([('type', '=', 'qweb')]) total_views = self.View.search_count([('type', '=', 'qweb')])
+40 -106
View File
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details. # Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging import logging
from lxml import etree from lxml import etree
import traceback
import os import os
import unittest import unittest
@@ -14,14 +13,12 @@ import werkzeug.utils
from functools import partial from functools import partial
import odoo import odoo
from odoo import api, models, registry from odoo import api, models
from odoo import SUPERUSER_ID from odoo import SUPERUSER_ID
from odoo.http import request from odoo.http import request
from odoo.tools import config
from odoo.tools.safe_eval import safe_eval from odoo.tools.safe_eval import safe_eval
from odoo.osv.expression import FALSE_DOMAIN, OR from odoo.osv.expression import FALSE_DOMAIN, OR
from odoo.addons.base.models.qweb import QWebException
from odoo.addons.http_routing.models.ir_http import ModelConverter, _guess_mimetype from odoo.addons.http_routing.models.ir_http import ModelConverter, _guess_mimetype
from odoo.addons.portal.controllers.portal import _build_url_w_params from odoo.addons.portal.controllers.portal import _build_url_w_params
@@ -239,7 +236,6 @@ class Http(models.AbstractModel):
'deletable': True, 'deletable': True,
'main_object': mypage, 'main_object': mypage,
}, mimetype=_guess_mimetype(ext)) }, mimetype=_guess_mimetype(ext))
return False
@classmethod @classmethod
def _serve_redirect(cls): def _serve_redirect(cls):
@@ -269,109 +265,47 @@ class Http(models.AbstractModel):
return False return False
@classmethod @classmethod
def _handle_exception(cls, exception): def _get_exception_code_values(cls, exception):
code = 500 # default code code, values = super(Http, cls)._get_exception_code_values(exception)
is_website_request = bool(getattr(request, 'is_frontend', False) and get_request_website()) if request.website.is_publisher() and isinstance(exception, werkzeug.exceptions.NotFound):
if not is_website_request: code = 'page_404'
# Don't touch non website requests exception handling values['path'] = request.httprequest.path[1:]
return super(Http, cls)._handle_exception(exception) return (code, values)
else:
@classmethod
def _get_values_500_error(cls, env, values, exception):
View = env["ir.ui.view"]
values = super(Http, cls)._get_values_500_error(env, values, exception)
if 'qweb_exception' in values:
try: try:
response = super(Http, cls)._handle_exception(exception) # exception.name might be int, string
exception_template = int(exception.name)
except:
exception_template = exception.name
view = View._view_obj(exception_template)
if exception.html and exception.html in view.arch:
values['view'] = view
else:
# There might be 2 cases where the exception code can't be found
# in the view, either the error is in a child view or the code
# contains branding (<div t-att-data="request.browse('ok')"/>).
et = etree.fromstring(view.with_context(inherit_branding=False).read_combined(['arch'])['arch'])
node = et.xpath(exception.path)
line = node is not None and etree.tostring(node[0], encoding='unicode')
if line:
values['view'] = View._views_get(exception_template).filtered(
lambda v: line in v.arch
)
values['view'] = values['view'] and values['view'][0]
# Needed to show reset template on translated pages (`_prepare_qcontext` will set it for main lang)
values['editable'] = request.uid and request.website.is_publisher()
return values
if isinstance(response, Exception): @classmethod
exception = response def _get_error_html(cls, env, code, values):
else: if code == 'page_404':
# if parent excplicitely returns a plain response, then we don't touch it return env['ir.ui.view'].render_template('website.%s' % code, values)
return response return super(Http, cls)._get_error_html(env, code, values)
except Exception as e:
if 'werkzeug' in config['dev_mode']:
raise e
exception = e
values = dict(
exception=exception,
traceback=traceback.format_exc(),
)
# only except_orm exceptions contain a message
if isinstance(exception, odoo.exceptions.except_orm):
values['error_message'] = exception.name
code = 400
if isinstance(exception, werkzeug.exceptions.HTTPException):
if exception.code is None:
# Hand-crafted HTTPException likely coming from abort(),
# usually for a redirect response -> return it directly
return exception
else:
code = exception.code
if isinstance(exception, odoo.exceptions.AccessError):
code = 403
if isinstance(exception, QWebException):
values.update(qweb_exception=exception)
# retro compatibility to remove in 12.2
exception.qweb = dict(message=exception.message, expression=exception.html)
if type(exception.error) == odoo.exceptions.AccessError:
code = 403
values.update(
status_message=werkzeug.http.HTTP_STATUS_CODES[code],
status_code=code,
)
view_id = code
if request.website.is_publisher() and isinstance(exception, werkzeug.exceptions.NotFound):
view_id = 'page_404'
values['path'] = request.httprequest.path[1:]
if not request.uid:
cls._auth_method_public()
with registry(request.env.cr.dbname).cursor() as cr:
env = api.Environment(cr, request.uid, request.env.context)
if code == 500:
logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
View = env["ir.ui.view"]
values['view'] = View
if 'qweb_exception' in values:
try:
# exception.name might be int, string
exception_template = int(exception.name)
except:
exception_template = exception.name
view = View._view_obj(exception_template)
if exception.html and exception.html in view.arch:
values['view'] = view
else:
# There might be 2 cases where the exception code can't be found
# in the view, either the error is in a child view or the code
# contains branding (<div t-att-data="request.browse('ok')"/>).
et = etree.fromstring(view.with_context(inherit_branding=False).read_combined(['arch'])['arch'])
node = et.xpath(exception.path)
line = node is not None and etree.tostring(node[0], encoding='unicode')
if line:
values['view'] = View._views_get(exception_template).filtered(
lambda v: line in v.arch
)
values['view'] = values['view'] and values['view'][0]
# Needed to show reset template on translated pages (`_prepare_qcontext` will set it for main lang)
values['editable'] = request.uid and request.website.is_publisher()
elif code == 403:
logger.warn("403 Forbidden:\n\n%s", values['traceback'])
elif code == 400:
logger.warn("400 Bad Request:\n\n%s", values['traceback'])
try:
html = env['ir.ui.view'].render_template('website.%s' % view_id, values)
except Exception:
html = env['ir.ui.view'].render_template('website.http_error', values)
return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas', def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas',
unique=False, filename=None, filename_field='name', download=False, unique=False, filename=None, filename_field='name', download=False,
+88 -240
View File
@@ -788,7 +788,7 @@
</template> </template>
<template id="page_404"> <template id="page_404">
<t t-call="website.404"> <t t-call="http_routing.404">
<div class="container"> <div class="container">
<div class="alert alert-info mt32"> <div class="alert alert-info mt32">
<p>This page does not exist, but you can create it as you are administrator of this site.</p> <p>This page does not exist, but you can create it as you are administrator of this site.</p>
@@ -800,256 +800,104 @@
</t> </t>
</template> </template>
<template id="http_error"> <template id="qweb_500" inherit_id="http_routing.500">
<t t-call="website.layout">
<div id="wrap">
<div class="oe_structure">
<h1 class="container mt32"><t t-esc="status_code"/>: <t t-esc="status_message"/></h1>
</div>
<t t-if="editable or debug">
<t t-call="website.http_error_debug"/>
</t>
</div>
</t>
</template>
<template id="error_message">
<p t-if="error_message">
<strong>Error message:</strong>
<pre t-esc="error_message"/>
</p>
</template>
<template id="http_error_debug">
<div class="container accordion mb32 mt32" id="debug_infos">
<div class="card" t-if="error_message">
<h4 class="card-header">
<a data-toggle="collapse" href="#error_main">Error</a>
</h4>
<div id="error_main" class="collapse show">
<div class="card-body">
<t t-call="website.error_message"/>
</div>
</div>
</div>
<div class="card" t-if="qweb_exception">
<h4 class="card-header">
<a data-toggle="collapse" href="#error_qweb">QWeb</a>
</h4>
<div id="error_qweb" class="collapse show">
<div class="card-body">
<p t-if="exception.message">
<strong>Error message:</strong>
<pre t-esc="exception.message"/>
</p>
<p>
The error occured while rendering the template <code t-esc="qweb_exception.name"/>
<t t-if="qweb_exception.html">and evaluating the following expression: <code t-esc="qweb_exception.html"/></t>
</p>
</div>
</div>
</div>
<div class="card" t-if="traceback">
<h4 class="card-header">
<a data-toggle="collapse" href="#error_traceback">Traceback</a>
</h4>
<div id="error_traceback" t-attf-class="collapse #{not error_message and not qweb_exception and 'show'}">
<div class="card-body">
<pre id="exception_traceback" t-esc="traceback"/>
</div>
</div>
</div>
</div>
</template>
<template id="400">
<t t-call="website.layout">
<div id="wrap">
<div class="container">
<h1 class="mt-5">Something went wrong.</h1>
<p>Take a look at the error message below.</p>
</div>
<t t-if="editable or request.session.debug">
<t t-call="website.http_error_debug"/>
</t>
<t t-else="">
<div class="container">
<t t-call="website.error_message"/>
</div>
</t>
</div>
</t>
</template>
<template id="403">
<t t-call="website.layout">
<div id="wrap">
<div class="container">
<h1 class="mt-5">403: Forbidden</h1>
<p>The page you were looking for could not be authorized.</p>
</div>
<t t-if="editable or request.session.debug">
<t t-call="website.http_error_debug"/>
</t>
<t t-else="">
<div class="container">
<t t-call="website.error_message"/>
</div>
</t>
</div>
</t>
</template>
<template id="404">
<t t-call="website.layout">
<div id="wrap">
<t t-raw="0"/>
<div class="oe_structure oe_empty">
<div class="container">
<h1 class="mt-5">404: Page not found!</h1>
<p>
The page you were looking for could not be found; it is possible you have
typed the address incorrectly, but it has most probably been removed due
to the recent website reorganisation.
</p>
<p>Maybe you were looking for one of these popular pages ?</p>
<ul>
<li><a href="/">Homepage</a></li>
<li><a href="/contactus">Contact Us</a></li>
</ul>
</div>
</div>
</div>
</t>
</template>
<template id="500">
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> <!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<!-- This template should not use any variable except those provided by website.ir_http._handle_exception --> <!-- This template should not use any variable except those provided by website.ir_http._handle_exception -->
<!-- no request.crsf_token, no theme style, no assets, ... cursor can be broken during rendering ! --> <!-- no request.crsf_token, no theme style, no assets, ... cursor can be broken during rendering ! -->
<!-- see test_05_reset_specific_view_controller_broken_request --> <!-- see test_05_reset_specific_view_controller_broken_request -->
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> <!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<html> <xpath expr="//script[last()]" position="before">
<head> <script type="text/javascript" src="/web/static/lib/bootstrap/js/modal.js"/>
<title t-esc="status_message">Internal Server Error</title> </xpath>
<t t-set="debug" t-value="True"/> <xpath expr="//style" position="after">
<t t-if='view'>
<link rel="stylesheet" href="/web/static/lib/bootstrap/css/bootstrap.css"/> <script>
<script src="/web/static/lib/jquery/jquery.js" type="text/javascript"/> $(document).ready(function() {
<script type="text/javascript" src="/web/static/lib/bootstrap/js/util.js"/> var button = $('.reset_templates_button');
<script type="text/javascript" src="/web/static/lib/bootstrap/js/collapse.js"/> button.click(function() {
<script type="text/javascript" src="/web/static/lib/bootstrap/js/modal.js"/> $('#reset_templates_mode').val($(this).data('mode'));
<style> var dialog = $('#reset_template_confirmation').modal('show');
html { var input = dialog.find('input[type="text"]').val('').focus();
font-size: 14px; var dialog_form = dialog.find('form');
} dialog_form.submit(function() {
</style> if (input.val() == dialog.find('.confirm_word').text()) {
dialog.modal('hide');
<t t-if='view'> button.prop('disabled', true).text('Working...');
<script> $('#reset_templates_form').attr('action', '/website/reset_template');
$(document).ready(function() { $('#reset_templates_form').trigger('submit');
var button = $('.reset_templates_button'); } else {
button.click(function() { input.val('').focus();
$('#reset_templates_mode').val($(this).data('mode')); }
var dialog = $('#reset_template_confirmation').modal('show');
var input = dialog.find('input[type="text"]').val('').focus();
var dialog_form = dialog.find('form');
dialog_form.submit(function() {
if (input.val() == dialog.find('.confirm_word').text()) {
dialog.modal('hide');
button.prop('disabled', true).text('Working...');
$('#reset_templates_form').attr('action', '/website/reset_template');
$('#reset_templates_form').trigger('submit');
} else {
input.val('').focus();
}
return false;
});
return false; return false;
}); });
return false;
}); });
</script> });
</t> </script>
</head> </t>
<body> </xpath>
<div t-if="view" role="dialog" id="reset_template_confirmation" class="modal" tabindex="-1" t-ignore="true"> <xpath expr="//div[@id='wrapwrap']" position="before">
<div class="modal-dialog"> <div t-if="view" role="dialog" id="reset_template_confirmation" class="modal" tabindex="-1" t-ignore="true">
<form role="form"> <div class="modal-dialog">
<div class="modal-content"> <form role="form">
<header class="modal-header"> <div class="modal-content">
<h4 class="modal-title">Reset templates</h4> <header class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button> <h4 class="modal-title">Reset templates</h4>
</header> <button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
<main class="modal-body"> </header>
<div class="form-group row mb0"> <main class="modal-body">
<label for="page-name" class="col-md-12 col-form-label"> <div class="form-group row mb0">
<p>The selected templates will be reset to their factory settings.</p> <label for="page-name" class="col-md-12 col-form-label">
</label> <p>The selected templates will be reset to their factory settings.</p>
</div> </label>
<div class="form-group row mb0">
<label for="page-name" class="col-md-9 col-form-label">
<p>Type '<i class="confirm_word">yes</i>' in the box below if you want to confirm.</p>
</label>
<div class="col-md-3 mt16">
<input type="text" id="page-name" class="form-control" required="required" placeholder="yes"/>
</div>
</div>
</main>
<footer class="modal-footer">
<button type="button" class="btn" data-dismiss="modal" aria-label="Cancel">Cancel</button>
<input type="submit" value="Confirm" class="btn btn-primary"/>
</footer>
</div>
</form>
</div>
</div>
<div id="wrapwrap">
<header>
<div class="navbar navbar-expand-md navbar-light bg-light">
<div class="container">
<div class="collapse navbar-collapse navbar-top-collapse">
<ul class="navbar-nav ml-auto" id="top_menu">
<li class="nav-item"><a href="/" class="nav-link">Home</a></li>
<li class="nav-item"><a href="javascript: window.history.back()" class="nav-link">Back</a></li>
</ul>
</div> </div>
</div> <div class="form-group row mb0">
<label for="page-name" class="col-md-9 col-form-label">
<p>Type '<i class="confirm_word">yes</i>' in the box below if you want to confirm.</p>
</label>
<div class="col-md-3 mt16">
<input type="text" id="page-name" class="form-control" required="required" placeholder="yes"/>
</div>
</div>
</main>
<footer class="modal-footer">
<button type="button" class="btn" data-dismiss="modal" aria-label="Cancel">Cancel</button>
<input type="submit" value="Confirm" class="btn btn-primary"/>
</footer>
</div> </div>
</header> </form>
<main>
<div class="oe_structure">
<h2 class="container mt32"><t t-esc="status_code"/>: <t t-esc="status_message"/></h2>
</div>
<div class="container" t-if="view and editable">
<div class="alert alert-danger" t-if="debug" role="alert">
<h4>Template fallback</h4>
<p>An error occured while rendering the template <code t-esc="qweb_exception.name"/>.</p>
<p>If this error is caused by a change of yours in the templates, you have the possibility to reset the template to its <strong>factory settings</strong>.</p>
<form action="#" method="post" id="reset_templates_form">
<ul>
<li>
<label>
<t t-esc="view.name"/>
</label>
</li>
</ul>
<input type="hidden" name="redirect" t-att-value="request.httprequest.path"/>
<input type="hidden" id="reset_templates_view_id" name="view_id" t-att-value="view.id"/>
<input type="hidden" id="reset_templates_mode" name="mode"/>
<button data-mode="soft" class="reset_templates_button btn btn-info">Restore previous version (soft reset).</button>
<button t-if="view.arch_fs" data-mode="hard" class="reset_templates_button btn btn-outline-danger">Reset to initial version (hard reset).</button>
</form>
</div>
</div>
<t t-if="editable or debug">
<t t-call="website.http_error_debug"/>
</t>
</main>
</div> </div>
</body> </div>
</html> </xpath>
<xpath expr="//div[@id='error_message']" position="after">
<div class="container" t-if="view and editable">
<div class="alert alert-danger" t-if="debug" role="alert">
<h4>Template fallback</h4>
<p>An error occured while rendering the template <code t-esc="qweb_exception.name"/>.</p>
<p>If this error is caused by a change of yours in the templates, you have the possibility to reset the template to its <strong>factory settings</strong>.</p>
<form action="#" method="post" id="reset_templates_form">
<ul>
<li>
<label>
<t t-esc="view.name"/>
</label>
</li>
</ul>
<input type="hidden" name="redirect" t-att-value="request.httprequest.path"/>
<input type="hidden" id="reset_templates_view_id" name="view_id" t-att-value="view.id"/>
<input type="hidden" id="reset_templates_mode" name="mode"/>
<button data-mode="soft" class="reset_templates_button btn btn-info">Restore previous version (soft reset).</button>
<button t-if="view.arch_fs" data-mode="hard" class="reset_templates_button btn btn-outline-danger">Reset to initial version (hard reset).</button>
</form>
</div>
</div>
</xpath>
</template>
<template id="portal_404" inherit_id="portal.portal_404">
<xpath expr="//li" position="before">
<li><a href="/">Homepage</a></li>
</xpath>
</template> </template>
<template id="robots"> <template id="robots">