[ADD] custom website ir.http#dispatch and rerouting

bzr revid: fme@openerp.com-20131127170432-z7d1w4ck03d7wwia
This commit is contained in:
Fabien Meghazi 2013-11-27 18:04:32 +01:00
parent d1d1754ff4
commit 07eaace3ee
3 changed files with 88 additions and 69 deletions

View File

@ -1,17 +1,20 @@
# -*- coding: utf-8 -*-
import traceback
import werkzeug.routing
import openerp
from openerp.addons.base import ir
from openerp.http import request
from openerp.osv import orm
from ..utils import slugify
from website import get_current_website
class ir_http(orm.AbstractModel):
_inherit = 'ir.http'
rerouting_limit = 10
def _get_converters(self):
return dict(
super(ir_http, self)._get_converters(),
@ -26,29 +29,82 @@ class ir_http(orm.AbstractModel):
else:
request.uid = request.session.uid
def _handle_403(self, exception):
return self._render_error(403, {
'error': exception.message
})
def _dispatch(self):
request.website = None
func = None
try:
func, arguments = self._find_handler()
request.cms = getattr(func, 'cms', False)
except werkzeug.exceptions.NotFound:
# either we have a language prefixed route, either a real 404
# in all cases, website processes them
request.cms = True
def _handle_404(self, exception):
return self._render_error(404)
if request.cms:
if func:
self._authenticate(getattr(func, 'auth', None))
else:
self._auth_method_public()
request.website = request.registry['website'].get_current_website(request.cr, request.uid, context=request.context)
langs = request.context['langs'] = [lg.code for lg in request.website.language_ids]
lang_cookie = request.httprequest.cookies.get('lang', None)
if lang_cookie in langs:
request.context['lang_cookie'] = lang_cookie
request.context['lang_default'] = request.website.default_lang_id.code
if not hasattr(request, 'lang'):
request.lang = request.context['lang_default']
request.context['lang'] = request.lang
request.website.preprocess_request(request)
if not func:
path = request.httprequest.path.split('/')
if path[1] in langs:
request.lang = request.context['lang'] = path.pop(1)
path = '/'.join(path) or '/'
return self.reroute(path)
return self._handle_404()
return super(ir_http, self)._dispatch()
def reroute(self, path):
if not hasattr(request, 'rerouting'):
request.rerouting = []
if path in request.rerouting:
raise Exception("Rerouting loop is forbidden")
request.rerouting.append(path)
if len(request.rerouting) > self.rerouting_limit:
raise Exception("Rerouting limit exceeded")
request.httprequest.environ['PATH_INFO'] = path
# void werkzeug cached_property. TODO: find a proper way to do this
for key in ('path', 'full_path', 'url', 'base_url'):
request.httprequest.__dict__.pop(key, None)
return self._dispatch()
def _handle_403(self, exception):
if getattr(request, 'cms', False) and request.website:
self._auth_method_public()
return self._render_error(403, {
'error': exception.message
})
raise exception
def _handle_404(self, exception=None):
if getattr(request, 'cms', False) and request.website:
return self._render_error(404)
raise request.not_found()
def _handle_500(self, exception):
# TODO: proper logging
return self._render_error(500, {
'exception': exception,
'traceback': traceback.format_exc(),
'qweb_template': getattr(exception, 'qweb_template', None),
'qweb_node': getattr(exception, 'qweb_node', None),
'qweb_eval': getattr(exception, 'qweb_eval', None),
})
if getattr(request, 'cms', False) and request.website:
return self._render_error(500, {
'exception': exception,
'traceback': traceback.format_exc(),
'qweb_template': getattr(exception, 'qweb_template', None),
'qweb_node': getattr(exception, 'qweb_node', None),
'qweb_eval': getattr(exception, 'qweb_eval', None),
})
raise exception
def _render_error(self, code, values=None):
self._auth_method_public()
if not hasattr(request, 'website'):
request.website = get_current_website()
request.website.preprocess_request(request)
return werkzeug.wrappers.Response(
request.website._render('website.%s' % code, values),
status=code,

View File

@ -3,7 +3,6 @@ import fnmatch
import functools
import inspect
import logging
import psycopg2
import math
import itertools
import urllib
@ -15,7 +14,7 @@ import werkzeug.exceptions
import werkzeug.wrappers
import openerp
from openerp.osv import orm, osv, fields
from openerp.osv import osv, fields
from openerp.tools.safe_eval import safe_eval
from openerp.addons.web import http
@ -26,44 +25,20 @@ logger = logging.getLogger(__name__)
def route(routes, *route_args, **route_kwargs):
def decorator(f):
new_routes = routes if isinstance(routes, list) else [routes]
f.cms = True
f.multilang = route_kwargs.get('multilang', False)
if f.multilang:
route_kwargs.pop('multilang')
for r in list(new_routes):
new_routes.append('/<string(length=5):lang_code>' + r)
@http.route(new_routes, *route_args, **route_kwargs)
@functools.wraps(f, assigned=functools.WRAPPER_ASSIGNMENTS + ('func_name',))
def wrap(*args, **kwargs):
request.route_lang = kwargs.pop('lang_code', None)
if not hasattr(request, 'website'):
request.multilang = f.multilang
request.website = get_current_website()
if request.route_lang:
lang_ok = [lg.code for lg in request.website.language_ids if lg.code == request.route_lang]
if not lang_ok:
return request.not_found()
request.website.preprocess_request(request)
return f(*args, **kwargs)
return wrap
f.multilang = route_kwargs.pop('multilang', False)
return http.route(routes, *route_args, **route_kwargs)(f)
return decorator
def get_current_website():
# TODO: Select website, currently hard coded
return request.registry['website'].browse(request.cr, request.uid, 1, context=request.context)
def url_for(path_or_uri, lang=None, keep_query=None):
location = path_or_uri.strip()
url = urlparse.urlparse(location)
if request and not url.netloc and not url.scheme:
location = urlparse.urljoin(request.httprequest.path, location)
lang = lang or request.context.get('lang')
langs = request.context.get('langs')
if location[0] == '/' and (len(langs) > 1 or lang):
if location[0] == '/' and len(langs) > 1 and lang != request.context['lang_default']:
ps = location.split('/')
lang = lang or request.context.get('lang')
if ps[1] in langs:
ps[1] = lang
else:
@ -164,38 +139,27 @@ class website(osv.osv):
self.public_user = self.pool[ref[0]].browse(cr, uid, ref[1])
return self.public_user
def get_current_website(self, cr, uid, context=None):
# TODO: Select website, currently hard coded
return self.pool['website'].browse(cr, uid, 1, context=context)
def preprocess_request(self, cr, uid, ids, request, context=None):
def redirect(url):
return werkzeug.utils.redirect(url_for(url))
request.redirect = redirect
if not hasattr(request, 'multilang'):
# TODO: try to get rid of this multilang attribute
request.multilang = False
is_public_user = request.uid == self.get_public_user(cr, uid, context).id
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
website_publisher_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_website_publisher')[1]
is_website_publisher = website_publisher_id in [g.id for g in user.groups_id]
# Select current language
if hasattr(request, 'route_lang'):
lang = request.route_lang
else:
lang = request.params.get('lang', None) or request.httprequest.cookies.get('lang', None)
if lang not in [lg.code for lg in request.website.language_ids]:
lang = request.website.default_lang_id.code
lang = request.context['lang']
is_master_lang = lang == request.website.default_lang_id.code
request.context.update({
'lang': lang,
'lang_selected': [lg for lg in request.website.language_ids if lg.code == lang],
'langs': [lg.code for lg in request.website.language_ids],
'multilang': request.multilang,
'is_public_user': is_public_user,
'is_master_lang': is_master_lang,
'editable': is_website_publisher,
'translatable': not is_public_user and not is_master_lang and request.multilang,
'translatable': not is_public_user and not is_master_lang,
})
def get_template(self, cr, uid, ids, template, context=None):

View File

@ -188,8 +188,7 @@
their performance.
</p>
</div>
<ul class="nav nav-pills js_language_selector" t-if="request.multilang and
(len(website.language_ids) &gt; 1 or editable)">
<ul class="nav nav-pills js_language_selector" t-if="(len(website.language_ids) &gt; 1 or editable)">
<li t-foreach="website.language_ids" t-as="lg">
<a t-att-href="url_for('', lang=lg.code)"
t-att-data-default-lang="editable and 'true' if lg.code == website.default_lang_id.code else None">
@ -197,7 +196,7 @@
</a>
</li>
<li t-if="editable">
<t t-set="url_return" t-value="request.multilang and url_for(request.httprequest.path, '[lang]') or request.httprequest.path"/>
<t t-set="url_return" t-value="url_for(request.httprequest.path, '[lang]')"/>
<a t-attf-href="/web#action=base.action_view_base_language_install&amp;website_id=#{website.id}&amp;url_return=#{url_return}">
<i class="icon-plus-sign"/>
Add a language...