summaryrefslogtreecommitdiff
path: root/addons/website/models/ir_http.py
diff options
context:
space:
mode:
authorJeremy Kersten <jke@odoo.com>2019-09-12 09:45:11 +0000
committerJeremy Kersten <jke@odoo.com>2019-09-30 13:58:14 +0000
commitbe8fc2296b3822baffe0bc68cb4b7efdfe53fa91 (patch)
tree08f0f825cfe2ffa652557f244f36880149d2f585 /addons/website/models/ir_http.py
parentb6b42ef73f4c517d9b7bc2da4909c13d7fe8f2c6 (diff)
[IMP] base, http_routing, website: allow custom routing rule
After this commit, you will be able (in technical mode) to update the url for the python controllers. Eg. You can now rename /shop in /garden and /shop/product/ in /garden/vegetable/ Most of urls will be replaced at fly in the renderd qweb, with the function url_for but all old urls will keep available. So if you access url /shop you will be automatically redirected to /garden (308 Permanent Redirect). As for cdn and other post-process of att, the automatically replacement in the rendered qweb is only done when you will be not website editor. But the new dispatch of URL will be applied in all cases. For developper, since it is Permanent Redirect, don't forget to clear cache or open chrome debug tool (with option 'Disable cache while DevTools is Open) to see your lasts changes. closes odoo/odoo#36555 Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
Diffstat (limited to 'addons/website/models/ir_http.py')
-rw-r--r--addons/website/models/ir_http.py66
1 files changed, 64 insertions, 2 deletions
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index ccfc2c531e4..2ad541d3e33 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -11,6 +11,8 @@ import werkzeug
import werkzeug.routing
import werkzeug.utils
+from functools import partial
+
import odoo
from odoo import api, models, registry
from odoo import SUPERUSER_ID
@@ -62,6 +64,58 @@ class Http(models.AbstractModel):
_inherit = 'ir.http'
@classmethod
+ def routing_map(cls, key=None):
+ key = key or (request and request.website_routing)
+ return super(Http, cls).routing_map(key=key)
+
+ @classmethod
+ def clear_caches(cls):
+ super(Http, cls)._clear_routing_map()
+ return super(Http, cls).clear_caches()
+
+ @classmethod
+ def _slug_matching(cls, adapter, endpoint, **kw):
+ for arg in kw:
+ if isinstance(kw[arg], models.BaseModel):
+ kw[arg] = kw[arg].with_user(request.uid)
+ qs = request.httprequest.query_string.decode('utf-8')
+ return adapter.build(endpoint, kw) + (qs and '?%s' % qs or '')
+
+ @classmethod
+ def _match(cls, path_info, key=None):
+ key = key or (request and request.website_routing)
+ return super(Http, cls)._match(path_info, key=key)
+
+ @classmethod
+ def _generate_routing_rules(cls, modules, converters):
+ website_id = request.website_routing
+ logger.debug("_generate_routing_rules for website: %s", website_id)
+ domain = [('redirect_type', 'in', ('rewrite', 'not_found')), '|', ('website_id', '=', False), ('website_id', '=', website_id)]
+
+ rewrites = dict([(x.url_from, x) for x in request.env['website.rewrite'].sudo().search(domain)])
+ cls._rewrite_len[website_id] = len(rewrites)
+
+ for url, endpoint, routing in super(Http, cls)._generate_routing_rules(modules, converters):
+ routing = dict(routing)
+ if url in rewrites:
+ rewrite = rewrites[url]
+ url_to = rewrite.url_to
+ if rewrite.redirect_type == 'rewrite':
+ logger.debug('Add rule %s for %s' % (url_to, website_id))
+ yield url_to, endpoint, routing # yield new url
+
+ if url != url_to:
+ logger.debug('Redirect from %s to %s for website %s' % (url, url_to, website_id))
+ _slug_matching = partial(cls._slug_matching, endpoint=endpoint)
+ routing['redirect_to'] = _slug_matching
+ yield url, endpoint, routing # yield original redirected to new url
+ elif rewrite.redirect_type == 'not_found':
+ logger.debug('Return 404 for %s for website %s' % (url, website_id))
+ continue
+ else:
+ yield url, endpoint, routing
+
+ @classmethod
def _get_converters(cls):
""" Get the converters list for custom url pattern werkzeug need to
match Rule. This override adds the website ones.
@@ -111,7 +165,11 @@ class Http(models.AbstractModel):
handling the original request, in which we should create the visitor. We ignore every other rerouting requests.
"""
is_rerouting = hasattr(request, 'routing_iteration')
+
+ request.website_routing = request.env['website'].get_current_website().id
+
response = super(Http, cls)._dispatch()
+
if not is_rerouting:
cls._register_website_track(response)
return response
@@ -186,8 +244,12 @@ class Http(models.AbstractModel):
@classmethod
def _serve_redirect(cls):
req_page = request.httprequest.path
- domain = [('url_from', '=', req_page)] + request.website.website_domain()
- return request.env['website.redirect'].search(domain, limit=1)
+ domain = [
+ ('redirect_type', 'in', ('redirect_301', 'redirect_302')),
+ ('url_from', '=', req_page)
+ ]
+ domain += request.website.website_domain()
+ return request.env['website.rewrite'].sudo().search(domain, limit=1)
@classmethod
def _serve_fallback(cls, exception):