diff --git a/addons/http_routing/models/ir_http.py b/addons/http_routing/models/ir_http.py index ebe37919fee..d75608f1205 100644 --- a/addons/http_routing/models/ir_http.py +++ b/addons/http_routing/models/ir_http.py @@ -402,16 +402,19 @@ class IrHttp(models.AbstractModel): return super()._match(path) # See /1, match a non website endpoint - with contextlib.suppress(NotFound): + try: rule, args = super()._match(path) routing = rule.endpoint.routing request.is_frontend = routing.get('website', False) request.is_frontend_multilang = request.is_frontend and routing.get('multilang', routing['type'] == 'http') if not request.is_frontend: return rule, args - - _, url_lang_str, *rest = path.split('/', 2) - path_no_lang = '/' + (rest[0] if rest else '') + except NotFound: + _, url_lang_str, *rest = path.split('/', 2) + path_no_lang = '/' + (rest[0] if rest else '') + else: + url_lang_str = '' + path_no_lang = path allow_redirect = request.httprequest.method != 'POST' # There is no user on the environment yet but the following code diff --git a/addons/website_links/tests/__init__.py b/addons/website_links/tests/__init__.py index 1e046233e6c..6ec97095797 100644 --- a/addons/website_links/tests/__init__.py +++ b/addons/website_links/tests/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- +from . import test_controller from . import test_ui diff --git a/addons/website_links/tests/test_controller.py b/addons/website_links/tests/test_controller.py new file mode 100644 index 00000000000..2e055cea56f --- /dev/null +++ b/addons/website_links/tests/test_controller.py @@ -0,0 +1,67 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.tests import tagged +from odoo.tests.common import HttpCase + + +@tagged('post_install', '-at_install') +class TestWebsiteLinksRussian(HttpCase): + """ + The /r URL prefix is considered as an alias to /ru by the "nearest + lang" algorithm of our http router (http_routing match). This test + suite makes sure that there the link-tracker "/r" controller is not + affected by any (wrong) /ru redirection. + """ + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.link = cls.env['link.tracker'].create({ + 'url': cls.base_url() + '/web/health', # no-op route + }) + + # Courtesy of website/tests/test_lang_url.py + website = cls.env.ref('website.default_website') + lang_en = cls.env.ref('base.lang_en') + lang_ru = cls.env['res.lang']._activate_lang('ru_RU') + website.language_ids = lang_en + lang_ru + website.default_lang_id = lang_en + + def test0_direct_link_tracker(self): + res = self.url_open(f'/r/{self.link.code}', allow_redirects=False) + res.raise_for_status() + self.assertEqual(res.status_code, 301, "Should be link-tracking redirection") + self.assertEqual(res.headers.get('Location'), self.link.url, + "Should not be redirected to /ru") + + def test1_russian_link_tracker(self): + res = self.url_open(f'/r/r/{self.link.code}', allow_redirects=False) + res.raise_for_status() + self.assertEqual(res.status_code, 301, "Should be a lang alias redirection") + self.assertEqual(res.headers.get('Location'), f'{self.base_url()}/ru/r/{self.link.code}', + "Should be redirected to /ru as r is an alias for ru (russian)") + + res = self.url_open(res.headers['Location'], allow_redirects=False) + res.raise_for_status() + self.assertEqual(res.status_code, 301, "Should be a link-tracking redirection") + self.assertEqual(res.headers.get('Location'), self.link.url, + "Should not be redirected to /ru") + + def test2_russian_page(self): + # This generate a new unused link + no_link_code = self.env['link.tracker.code']._get_random_code_strings()[0] + + view = self.env['ir.ui.view'].create({ + 'name': 'Base', + 'type': 'qweb', + 'arch': '