diff options
| author | Christophe Simonis <chs@odoo.com> | 2019-09-13 18:07:59 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2019-09-13 18:07:59 +0200 |
| commit | 6c948c36bbf72dd896e0bff03aa7fbddadcbb0cd (patch) | |
| tree | f8620905c011735d8a3c340c46d1417a54a75972 /addons/website/models/website.py | |
| parent | 48503fcf08eac6fed12e080d4f501f9bbc8d257d (diff) | |
| parent | 197474e5b9ad43ab2d587a98136a1a809ce9a2e7 (diff) | |
[MERGE] forward port branch saas-12.5 up to 197474e5b9a
Diffstat (limited to 'addons/website/models/website.py')
| -rw-r--r-- | addons/website/models/website.py | 117 |
1 files changed, 81 insertions, 36 deletions
diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 8ce3d46568a..0ddca6810e2 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -7,7 +7,9 @@ import logging import hashlib import re + from werkzeug import urls +from werkzeug.datastructures import OrderedMultiDict from werkzeug.exceptions import NotFound from odoo import api, fields, models, tools @@ -56,7 +58,6 @@ class Website(models.Model): company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.company, required=True) language_ids = fields.Many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages', default=_active_languages) default_lang_id = fields.Many2one('res.lang', string="Default Language", default=_default_language, required=True) - default_lang_code = fields.Char("Default language code", related='default_lang_id.code', store=True, readonly=False) auto_redirect_lang = fields.Boolean('Autoredirect Language', default=True, help="Should users be redirected to their browser's language") def _default_social_facebook(self): @@ -156,7 +157,8 @@ class Website(models.Model): public_user_to_change_websites = self.env['website'] self._handle_favicon(values) - self._get_languages.clear_cache(self) + self.clear_caches() + if 'company_id' in values and 'user_id' not in values: public_user_to_change_websites = self.filtered(lambda w: w.sudo().user_id.company_id.id != values['company_id']) if public_user_to_change_websites: @@ -437,45 +439,42 @@ class Website(models.Model): # Languages # ---------------------------------------------------------- - def get_languages(self): + def _get_alternate_languages(self, canonical_params): self.ensure_one() - return self._get_languages() - @tools.cache('self.id') - def _get_languages(self): - return [(lg.code, lg.name) for lg in self.language_ids] + if not self._is_canonical_url(canonical_params=canonical_params): + # no hreflang on non-canonical pages + return [] + + languages = self.language_ids + if len(languages) <= 1: + # no hreflang if no alternate language + return [] - def get_alternate_languages(self, req=None): langs = [] - if req is None: - req = request.httprequest - default = self.get_current_website().default_lang_code shorts = [] - def get_url_localized(router, lang): - arguments = dict(request.endpoint_arguments) - for key, val in list(arguments.items()): - if isinstance(val, models.BaseModel): - arguments[key] = val.with_context(lang=lang) - return router.build(request.endpoint, arguments) - - router = request.httprequest.app.get_db_router(request.db).bind('') - for code, dummy in self.get_languages(): - lg_path = ('/' + code) if code != default else '' - lg_codes = code.split('_') - shorts.append(lg_codes[0]) - uri = get_url_localized(router, code) if request.endpoint else request.httprequest.path - if req.query_string: - uri += u'?' + req.query_string.decode('utf-8') - lang = { + for lg in languages: + lg_codes = lg.code.split('_') + short = lg_codes[0] + shorts.append(short) + langs.append({ 'hreflang': ('-'.join(lg_codes)).lower(), - 'short': lg_codes[0], - 'href': req.url_root[0:-1] + lg_path + uri, - } - langs.append(lang) + 'short': short, + 'href': self._get_canonical_url_localized(lang=lg, canonical_params=canonical_params), + }) + + # if there is only one region for a language, use only the language code for lang in langs: if shorts.count(lang['short']) == 1: lang['hreflang'] = lang['short'] + + # add the default + langs.append({ + 'hreflang': 'x-default', + 'href': self._get_canonical_url_localized(lang=self.default_lang_id, canonical_params=canonical_params), + }) + return langs # ---------------------------------------------------------- @@ -741,9 +740,6 @@ class Website(models.Model): domain_part, url = rule.build(value, append_unknown=False) if not query_string or query_string.lower() in url.lower(): page = {'loc': url} - for key, val in value.items(): - if key.startswith('__'): - page[key[2:]] = val if url in ('/sitemap.xml',): continue if url in url_set: @@ -767,9 +763,9 @@ class Website(models.Model): for page in pages: record = {'loc': page['url'], 'id': page['id'], 'name': page['name']} if page.view_id and page.view_id.priority != 16: - record['__priority'] = min(round(page.view_id.priority / 32.0, 1), 1) + record['priority'] = min(round(page.view_id.priority / 32.0, 1), 1) if page['write_date']: - record['__lastmod'] = page['write_date'].date() + record['lastmod'] = page['write_date'].date() yield record def get_website_pages(self, domain=[], order='name', limit=None): @@ -835,6 +831,55 @@ class Website(models.Model): self.ensure_one() return self._get_http_domain() or super(BaseModel, self).get_base_url() + def _get_canonical_url_localized(self, lang, canonical_params): + """Returns the canonical URL for the current request with translatable + elements appropriately translated in `lang`. + + If `request.endpoint` is not true, returns the current `path` instead. + + `url_quote_plus` is applied on the returned path. + """ + self.ensure_one() + if request.endpoint: + router = request.httprequest.app.get_db_router(request.db).bind('') + arguments = dict(request.endpoint_arguments) + for key, val in list(arguments.items()): + if isinstance(val, models.BaseModel): + if val.env.context.get('lang') != lang.url_code: + arguments[key] = val.with_context(lang=lang.url_code) + path = router.build(request.endpoint, arguments) + else: + # The build method returns a quoted URL so convert in this case for consistency. + path = urls.url_quote_plus(request.httprequest.path, safe='/') + lang_path = ('/' + lang.url_code) if lang != self.default_lang_id else '' + canonical_query_string = '?%s' % urls.url_encode(canonical_params) if canonical_params else '' + return self.get_base_url() + lang_path + path + canonical_query_string + + def _get_canonical_url(self, canonical_params): + """Returns the canonical URL for the current request.""" + self.ensure_one() + return self._get_canonical_url_localized(lang=request.lang, canonical_params=canonical_params) + + def _is_canonical_url(self, canonical_params): + """Returns whether the current request URL is canonical.""" + self.ensure_one() + # Compare OrderedMultiDict because the order is important, there must be + # only one canonical and not params permutations. + params = request.httprequest.args + canonical_params = canonical_params or OrderedMultiDict() + if params != canonical_params: + return False + # Compare URL at the first rerouting iteration (if available) because + # it's the one with the language in the path. + # It is important to also test the domain of the current URL. + current_url = request.httprequest.url_root[:-1] + (hasattr(request, 'rerouting') and request.rerouting[0] or request.httprequest.path) + canonical_url = self._get_canonical_url_localized(lang=request.lang, canonical_params=None) + # A request path with quotable characters (such as ",") is never + # canonical because request.httprequest.base_url is always unquoted, + # and canonical url is always quoted, so it is never possible to tell + # if the current URL is indeed canonical or not. + return current_url == canonical_url + class BaseModel(models.AbstractModel): _inherit = 'base' |
