1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import re
import werkzeug
from odoo import models, fields, api, _
from odoo.exceptions import AccessDenied, ValidationError
import logging
_logger = logging.getLogger(__name__)
class WebsiteRoute(models.Model):
_rec_name = 'path'
_name = 'website.route'
_description = "All Website Route"
_order = 'path'
path = fields.Char('Route')
@api.model
def _name_search(self, name='', args=None, operator='ilike', limit=100, name_get_uid=None):
res = super(WebsiteRoute, self)._name_search(name=name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid)
if not len(res):
self._refresh()
return super(WebsiteRoute, self)._name_search(name=name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid)
return res
def _refresh(self):
_logger.debug("Refreshing website.route")
ir_http = self.env['ir.http']
tocreate = []
paths = {rec.path: rec for rec in self.search([])}
for url, _, routing in ir_http._generate_routing_rules(self.pool._init_modules, converters=ir_http._get_converters()):
if 'GET' in (routing.get('methods') or ['GET']):
if paths.get(url):
paths.pop(url)
else:
tocreate.append({'path': url})
if tocreate:
_logger.info("Add %d website.route" % len(tocreate))
self.create(tocreate)
if paths:
find = self.search([('path', 'in', list(paths.keys()))])
_logger.info("Delete %d website.route" % len(find))
find.unlink()
class WebsiteRewrite(models.Model):
_name = 'website.rewrite'
_description = "Website rewrite"
name = fields.Char('Name', required=True)
website_id = fields.Many2one('website', string="Website", ondelete='cascade', index=True)
active = fields.Boolean(default=True)
url_from = fields.Char('URL from', index=True)
route_id = fields.Many2one('website.route')
url_to = fields.Char("URL to")
redirect_type = fields.Selection([
('404', '404 Not Found'),
('301', '301 Moved permanently'),
('302', '302 Moved temporarily'),
('308', '308 Redirect / Rewrite'),
], string='Action', default="302",
help='''Type of redirect/Rewrite:\n
301 Moved permanently: The browser will keep in cache the new url.
302 Moved temporarily: The browser will not keep in cache the new url and ask again the next time the new url.
404 Not Found: If you want remove a specific page/controller (e.g. Ecommerce is installed, but you don't want /shop on a specific website)
308 Redirect / Rewrite: If you want rename a controller with a new url. (Eg: /shop -> /garden - Both url will be accessible but /shop will automatically be redirected to /garden)
''')
sequence = fields.Integer()
@api.onchange('route_id')
def _onchange_route_id(self):
self.url_from = self.route_id.path
self.url_to = self.route_id.path
@api.constrains('url_to', 'url_from', 'redirect_type')
def _check_url_to(self):
for rewrite in self:
if rewrite.redirect_type == '308':
if not rewrite.url_to:
raise ValidationError(_('"URL to" can not be empty.'))
elif not rewrite.url_to.startswith('/'):
raise ValidationError(_('"URL to" must start with a leading slash.'))
for param in re.findall('/<.*?>', rewrite.url_from):
if param not in rewrite.url_to:
raise ValidationError(_('"URL to" must contain parameter %s used in "URL from".') % param)
for param in re.findall('/<.*?>', rewrite.url_to):
if param not in rewrite.url_from:
raise ValidationError(_('"URL to" cannot contain parameter %s which is not used in "URL from".') % param)
try:
converters = self.env['ir.http']._get_converters()
routing_map = werkzeug.routing.Map(strict_slashes=False, converters=converters)
rule = werkzeug.routing.Rule(rewrite.url_to)
routing_map.add(rule)
except ValueError as e:
raise ValidationError(_('"URL to" is invalid: %s') % e)
def name_get(self):
result = []
for rewrite in self:
name = "%s - %s" % (rewrite.redirect_type, rewrite.name)
result.append((rewrite.id, name))
return result
@api.model
def create(self, vals):
res = super(WebsiteRewrite, self).create(vals)
self._invalidate_routing()
return res
def write(self, vals):
res = super(WebsiteRewrite, self).write(vals)
self._invalidate_routing()
return res
def unlink(self):
res = super(WebsiteRewrite, self).unlink()
self._invalidate_routing()
return res
def _invalidate_routing(self):
# call clear_caches on this worker to reload routing table
self.env['ir.http'].clear_caches()
def refresh_routes(self):
self.env['website.route']._refresh()
|