File: test_lang_url.py

package info (click to toggle)
odoo 18.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 878,716 kB
  • sloc: javascript: 927,937; python: 685,670; xml: 388,524; sh: 1,033; sql: 415; makefile: 26
file content (160 lines) | stat: -rw-r--r-- 7,402 bytes parent folder | download
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import json
import lxml.html
from urllib.parse import urlparse

from odoo.addons.website.tools import MockRequest
from odoo.tests import HttpCase, tagged


@tagged('-at_install', 'post_install')
class TestLangUrl(HttpCase):
    def setUp(self):
        super(TestLangUrl, self).setUp()

        # Simulate multi lang without loading translations
        self.website = self.env.ref('website.default_website')
        self.lang_fr = self.env['res.lang']._activate_lang('fr_FR')
        self.lang_fr.write({'url_code': 'fr'})
        self.website.language_ids = self.env.ref('base.lang_en') + self.lang_fr
        self.website.default_lang_id = self.env.ref('base.lang_en')

    def test_01_url_lang(self):
        with MockRequest(self.env, website=self.website):
            self.assertEqual(self.env['ir.http']._url_for('', '[lang]'), '/[lang]/mockrequest', "`[lang]` is used to be replaced in the url_return after installing a language, it should not be replaced or removed.")

    def test_02_url_redirect(self):
        url = '/fr_WHATEVER/contactus'
        r = self.url_open(url)
        self.assertEqual(r.status_code, 200)
        self.assertURLEqual(r.url, '/fr/contactus', f"fr_WHATEVER should be forwarded to 'fr_FR' lang as closest match, url: {r.url}")

        url = '/fr_FR/contactus'
        r = self.url_open(url)
        self.assertEqual(r.status_code, 200)
        self.assertURLEqual(r.url, '/fr/contactus', f"lang in url should use url_code ('fr' in this case), url: {r.url}")

    def test_03_url_cook_lang_not_available(self):
        """ An activated res.lang should not be displayed in the frontend if not a website lang. """
        self.website.language_ids = self.env.ref('base.lang_en')
        r = self.url_open('/fr/contactus')

        if 'lang="en-US"' not in r.text:
            doc = lxml.html.document_fromstring(r.text)
            self.assertEqual(doc.get('lang'), 'en-US', "french should not be displayed as not a frontend lang")

    def test_04_url_cook_lang_not_available(self):
        """ `nearest_lang` should filter out lang not available in frontend.
        Eg: 1. go in backend in english -> request.context['lang'] = `en_US`
            2. go in frontend, the request.context['lang'] is passed through
               `nearest_lang` which should not return english. More then a
               misbehavior it will crash in website language selector template.
        """
        # 1. Load backend
        self.authenticate('admin', 'admin')
        r = self.url_open('/odoo')
        self.assertEqual(r.status_code, 200)

        for line in r.text.splitlines():
            _, match, session_info_str = line.partition('odoo.__session_info__ = ')
            if match:
                session_info = json.loads(session_info_str[:-1])
                self.assertEqual(session_info['user_context']['lang'], 'en_US', "ensure english was loaded")
                break
        else:
            raise ValueError('Session info not found in web page')

        # 2. Remove en_US from frontend
        self.website.language_ids = self.lang_fr
        self.website.default_lang_id = self.lang_fr

        # 3. Ensure visiting /contactus do not crash
        url = '/contactus'
        r = self.url_open(url)
        self.assertEqual(r.status_code, 200)

        if 'lang="fr-FR"' not in r.text:
            doc = lxml.html.document_fromstring(r.text)
            self.assertEqual(doc.get('lang'), 'fr-FR', "Ensure contactus did not soft crash + loaded in correct lang")

    def test_05_invalid_ipv6_url(self):
        view = self.env['ir.ui.view'].create({
            'name': 'Base',
            'type': 'qweb',
            'arch': '<a id="foo" href="http://]">Invalid IP V6</a>',
            'key': 'test.invalid_ipv6_view',
        })

        self.env['website.page'].create({
            'view_id': view.id,
            'url': '/page_invalid_ipv6_url',
            'is_published': True,
        })
        r = self.url_open('/page_invalid_ipv6_url')
        self.assertEqual(r.status_code, 200, 'The page must still load despite the invalid link')
        doc = lxml.html.document_fromstring(r.text)
        [anchor] = doc.xpath('//a[@id="foo"]')
        self.assertEqual(anchor.get('href'), 'http://]', 'The invalid IP URL must be left untouched')

    def test_06_reroute_unicode(self):
        res = self.url_open('/fr/привет')
        self.assertEqual(res.status_code, 404, "Rerouting didn't crash because of unicode path")

        res = self.url_open('/fr/path?привет=1')
        self.assertEqual(res.status_code, 404, "Rerouting didn't crash because of unicode query-string")

    def test_07_nolang_prefix_underscore(self):
        res = self.url_open('/_not_a_lang', allow_redirects=False)
        self.assertEqual(res.status_code, 404, "Should not consider /_not_a_lang as a lang")
        self.assertURLEqual(res.url, '/_not_a_lang', "Should use /_not_a_lang as the path and not a lang")


@tagged('-at_install', 'post_install')
class TestControllerRedirect(TestLangUrl):
    def setUp(self):
        self.page = self.env['website.page'].create({
            'name': 'Test View',
            'type': 'qweb',
            'arch': '''<t t-call="website.layout">Test View Page</t>''',
            'key': 'test.test_view',
            'url': '/page_1',
            'is_published': True,
        })
        super().setUp()

    def test_01_controller_redirect(self):
        """ Trailing slash URLs should be redirected to non-slash URLs (unless
            the controller explicitly specifies a trailing slash in the route).
        """

        def assertUrlRedirect(url, expected_url, msg="", code=301):
            if not msg:
                msg = 'Url <%s> differ from <%s>.' % (url, expected_url)

            r = self.url_open(url, head=True)
            self.assertEqual(r.status_code, code)
            parsed_location = urlparse(r.headers.get('Location', ''))
            parsed_expected_url = urlparse(expected_url)
            self.assertEqual(parsed_location.path, parsed_expected_url.path, msg)
            self.assertEqual(parsed_location.query, parsed_expected_url.query, msg)

        self.authenticate('admin', 'admin')

        # Controllers
        assertUrlRedirect('/my/', '/my', "Check for basic controller.")
        assertUrlRedirect('/my/?a=b', '/my?a=b', "Check for basic controller + URL params.")
        # website.page
        assertUrlRedirect('/page_1/', '/page_1', "Check for website.page.")
        assertUrlRedirect('/page_1/?a=b', '/page_1?a=b', "Check for website.page + URL params.")

        # == Same with language ==
        # Controllers
        assertUrlRedirect('/fr/my/', '/fr/my', "Check for basic controller with language in URL.")
        assertUrlRedirect('/fr/my/?a=b', '/fr/my?a=b', "Check for basic controller with language in URL + URL params.")
        # Homepage (which is a controller)
        assertUrlRedirect('/fr/', '/fr', "Check for homepage + language.")
        assertUrlRedirect('/fr/?a=b', '/fr?a=b', "Check for homepage + language + URL params")
        # website.page
        assertUrlRedirect('/fr/page_1/', '/fr/page_1', "Check for website.page with language in URL.")
        assertUrlRedirect('/fr/page_1/?a=b', '/fr/page_1?a=b', "Check for website.page with language in URL + URL params.")