==== Short version ==== Google is deprecating Universal Analytics in July 2023 and Google Sign-In in March 2023. Google Analytics Embed API is based on Sign-In, meaning it won't work anymore. It actually already doesn't work anymore for accounts created somewhere after mid-2020 apparently. There is no plan for now for Google to allow Analytics 4 dashboard to be embed in external website. We therefore can't do anything to keep the Google Analytics dashboard in Odoo. In previous stable version, it was kept but is displaying a warning about it (as until mid 2023 old accounts can still embed it). All this is about the embed dashboard, not the tracking in itself for which Odoo is already adapted in Odoo 15.0 for Analytics 4. ==== Detailed version (following short version, read it first) ==== - Universal Analytics EOL July 2023, see [1]. - It will be replaced by Analytics 4 for which Odoo is already ready and actually using it since version 15.0 with [2]. - Google Sign-In EOL March 2023, see [3]. Analytics Embed API was based on it, it won't work anymore. - There is no plan (for now) for Google to allow Analytics 4 to be able to be embed in external websites. They seem to just have dropped the "feature". This was confirmed by Google here [4] and indirectly here [5] in the DOC: `Note: This API does not support Google Analytics 4 (GA4) properties` - While the EOL is planed for 2023, the dashboard integration is already not working anymore for new accounts. - Old projects/keys/accounts can still embed their analytics dashboard. The threshold seems to be somewhere mid-2020, according to [6]. It seems to be accurate as my own key from 2018 still works, while my keys from 2021 do not. ==== Fix ==== - In stable, warn user about it in their Odoo Analytics dashboard (this PR) and also add a warning about that on the doc. - In master, simply drop the whole google analytics dashboard integration and remove the doc about it, see [7]. ==== Useful links ==== [1]: https://support.google.com/analytics/answer/11583528?hl=en [2]: https://github.com/odoo/odoo/commit/78bc86cbeccfc5df16218aee2b0d7c501e5c05b5 [3]: https://developers.googleblog.com/2022/03/gis-jsweb-authz-migration.html [4]: https://issuetracker.google.com/issues/233738709?pli=1 [5]: https://developers.google.com/analytics/devguides/reporting/embed/v1 [6]: https://support.google.com/analytics/answer/11583832 [7]: https://www.odoo.com/documentation/15.0/applications/websites/website/optimize/google_analytics_dashboard.html Finally, note that it means that from July 2023 to Octobre 2023, while Odoo 14.0 is still supported, Google Analytics won't work anymore in that version as it will still be designed for Universal Analytics and not Analytics 4. opw-2710910 opw-2855405 opw-2881515 opw-2892370 task-2790245 task-2820890 closes odoo/odoo#96280 X-original-commit: d065595f77790fb5ab9480f6de5b88549352324b Related: odoo/enterprise#29666 Related: odoo/upgrade#3698 Related: odoo/documentation#2499 Signed-off-by: Romain Derie (rde) <rde@odoo.com>
245 lines
8.7 KiB
Python
245 lines
8.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
|
|
from odoo import api, fields, models
|
|
from odoo.exceptions import UserError
|
|
from odoo.tools.translate import _
|
|
|
|
from werkzeug import urls
|
|
|
|
|
|
class ResConfigSettings(models.TransientModel):
|
|
_inherit = 'res.config.settings'
|
|
|
|
def _default_website(self):
|
|
return self.env['website'].search([('company_id', '=', self.env.company.id)], limit=1)
|
|
|
|
website_id = fields.Many2one(
|
|
'website',
|
|
string="website",
|
|
default=_default_website, ondelete='cascade')
|
|
website_name = fields.Char(
|
|
'Website Name',
|
|
related='website_id.name',
|
|
readonly=False)
|
|
website_domain = fields.Char(
|
|
'Website Domain',
|
|
related='website_id.domain',
|
|
readonly=False)
|
|
website_country_group_ids = fields.Many2many(
|
|
related='website_id.country_group_ids',
|
|
readonly=False)
|
|
website_company_id = fields.Many2one(
|
|
related='website_id.company_id',
|
|
string='Website Company',
|
|
readonly=False)
|
|
website_logo = fields.Binary(
|
|
related='website_id.logo',
|
|
readonly=False)
|
|
language_ids = fields.Many2many(
|
|
related='website_id.language_ids',
|
|
relation='res.lang',
|
|
readonly=False)
|
|
website_language_count = fields.Integer(
|
|
string='Number of languages',
|
|
compute='_compute_website_language_count',
|
|
readonly=True)
|
|
website_default_lang_id = fields.Many2one(
|
|
string='Default language',
|
|
related='website_id.default_lang_id',
|
|
readonly=False)
|
|
website_default_lang_code = fields.Char(
|
|
'Default language code',
|
|
related='website_id.default_lang_id.code',
|
|
readonly=False)
|
|
shared_user_account = fields.Boolean(
|
|
string="Shared Customer Accounts",
|
|
compute='_compute_shared_user_account',
|
|
inverse='_inverse_shared_user_account')
|
|
website_cookies_bar = fields.Boolean(
|
|
related='website_id.cookies_bar',
|
|
readonly=False)
|
|
google_analytics_key = fields.Char(
|
|
'Google Analytics Key',
|
|
related='website_id.google_analytics_key',
|
|
readonly=False)
|
|
google_search_console = fields.Char(
|
|
'Google Search Console',
|
|
related='website_id.google_search_console',
|
|
readonly=False)
|
|
plausible_shared_key = fields.Char(
|
|
'Plausible auth Key',
|
|
related='website_id.plausible_shared_key',
|
|
readonly=False)
|
|
plausible_site = fields.Char(
|
|
'Plausible Site (e.g. domain.com)',
|
|
related='website_id.plausible_site',
|
|
readonly=False)
|
|
cdn_activated = fields.Boolean(
|
|
related='website_id.cdn_activated',
|
|
readonly=False)
|
|
cdn_url = fields.Char(
|
|
related='website_id.cdn_url',
|
|
readonly=False)
|
|
cdn_filters = fields.Text(
|
|
related='website_id.cdn_filters',
|
|
readonly=False)
|
|
auth_signup_uninvited = fields.Selection(
|
|
compute="_compute_auth_signup_uninvited",
|
|
inverse="_inverse_auth_signup_uninvited",
|
|
# Remove any default value and let the compute handle it
|
|
config_parameter=False, default=None)
|
|
|
|
favicon = fields.Binary(
|
|
'Favicon',
|
|
related='website_id.favicon',
|
|
readonly=False)
|
|
social_default_image = fields.Binary(
|
|
'Default Social Share Image',
|
|
related='website_id.social_default_image',
|
|
readonly=False)
|
|
|
|
group_multi_website = fields.Boolean(
|
|
"Multi-website",
|
|
implied_group="website.group_multi_website")
|
|
has_google_analytics = fields.Boolean(
|
|
"Google Analytics",
|
|
compute='_compute_has_google_analytics',
|
|
inverse='_inverse_has_google_analytics')
|
|
has_google_search_console = fields.Boolean(
|
|
"Console Google Search",
|
|
compute='_compute_has_google_search_console',
|
|
inverse='_inverse_has_google_search_console')
|
|
has_default_share_image = fields.Boolean(
|
|
"Use a image by default for sharing",
|
|
compute='_compute_has_default_share_image',
|
|
inverse='_inverse_has_default_share_image')
|
|
has_plausible_shared_key = fields.Boolean(
|
|
"Plausible Analytics",
|
|
compute='_compute_has_plausible_shared_key',
|
|
inverse='_inverse_has_plausible_shared_key')
|
|
module_website_livechat = fields.Boolean()
|
|
module_marketing_automation = fields.Boolean()
|
|
|
|
@api.depends('website_id')
|
|
def _compute_shared_user_account(self):
|
|
for config in self:
|
|
config.shared_user_account = not config.website_id.specific_user_account
|
|
|
|
@api.onchange('plausible_shared_key')
|
|
def _onchange_shared_key(self):
|
|
for config in self:
|
|
value = config.plausible_shared_key
|
|
if value and value.startswith('http'):
|
|
try:
|
|
url = urls.url_parse(value)
|
|
config.plausible_shared_key = urls.url_decode(url.query).get('auth', '')
|
|
config.plausible_site = url.path.split('/')[-1]
|
|
except Exception: # noqa
|
|
pass
|
|
|
|
def _inverse_shared_user_account(self):
|
|
for config in self:
|
|
config.website_id.specific_user_account = not config.shared_user_account
|
|
|
|
@api.depends('website_id.auth_signup_uninvited')
|
|
def _compute_auth_signup_uninvited(self):
|
|
for config in self:
|
|
# Default to `b2b` in case no website is set to avoid not being
|
|
# able to save.
|
|
config.auth_signup_uninvited = config.website_id.auth_signup_uninvited or 'b2b'
|
|
|
|
def _inverse_auth_signup_uninvited(self):
|
|
for config in self:
|
|
config.website_id.auth_signup_uninvited = config.auth_signup_uninvited
|
|
|
|
@api.depends('website_id')
|
|
def _compute_has_plausible_shared_key(self):
|
|
for config in self:
|
|
config.has_plausible_shared_key = bool(config.plausible_shared_key)
|
|
|
|
def _inverse_has_plausible_shared_key(self):
|
|
for config in self:
|
|
if config.has_plausible_shared_key:
|
|
continue
|
|
config.plausible_shared_key = False
|
|
config.plausible_site = False
|
|
|
|
@api.depends('website_id')
|
|
def _compute_has_google_analytics(self):
|
|
for config in self:
|
|
config.has_google_analytics = bool(config.google_analytics_key)
|
|
|
|
def _inverse_has_google_analytics(self):
|
|
for config in self:
|
|
if config.has_google_analytics:
|
|
continue
|
|
config.google_analytics_key = False
|
|
|
|
@api.depends('website_id')
|
|
def _compute_has_google_search_console(self):
|
|
for config in self:
|
|
config.has_google_search_console = bool(config.google_search_console)
|
|
|
|
def _inverse_has_google_search_console(self):
|
|
for config in self:
|
|
if not config.has_google_search_console:
|
|
config.google_search_console = False
|
|
|
|
@api.depends('website_id')
|
|
def _compute_has_default_share_image(self):
|
|
for config in self:
|
|
config.has_default_share_image = bool(config.social_default_image)
|
|
|
|
def _inverse_has_default_share_image(self):
|
|
for config in self:
|
|
if not config.has_default_share_image:
|
|
config.social_default_image = False
|
|
|
|
@api.onchange('language_ids')
|
|
def _onchange_language_ids(self):
|
|
# If current default language is removed from language_ids
|
|
# update the website_default_lang_id
|
|
language_ids = self.language_ids._origin
|
|
if not language_ids:
|
|
self.website_default_lang_id = False
|
|
elif self.website_default_lang_id not in language_ids:
|
|
self.website_default_lang_id = language_ids[0]
|
|
|
|
@api.depends('language_ids')
|
|
def _compute_website_language_count(self):
|
|
for config in self:
|
|
config.website_language_count = len(config.language_ids)
|
|
|
|
def action_website_create_new(self):
|
|
return {
|
|
'view_mode': 'form',
|
|
'view_id': self.env.ref('website.view_website_form_view_themes_modal').id,
|
|
'res_model': 'website',
|
|
'type': 'ir.actions.act_window',
|
|
'target': 'new',
|
|
'res_id': False,
|
|
}
|
|
|
|
def action_open_robots(self):
|
|
self.website_id._force()
|
|
return {
|
|
'name': _("Robots.txt"),
|
|
'view_mode': 'form',
|
|
'res_model': 'website.robots',
|
|
'type': 'ir.actions.act_window',
|
|
"views": [[False, "form"]],
|
|
'target': 'new',
|
|
}
|
|
|
|
def action_ping_sitemap(self):
|
|
if not self.website_id.domain:
|
|
raise UserError(_("You haven't defined your domain"))
|
|
|
|
return {
|
|
'type': 'ir.actions.act_url',
|
|
'url': 'http://www.google.com/ping?sitemap=%s/sitemap.xml' % self.website_id.domain,
|
|
'target': 'new',
|
|
}
|