diff --git a/addons/website/controllers/backend.py b/addons/website/controllers/backend.py index c5cf4822c06..34245145c5b 100644 --- a/addons/website/controllers/backend.py +++ b/addons/website/controllers/backend.py @@ -3,7 +3,6 @@ from odoo import http from odoo.http import request -from odoo.tools.translate import _ class WebsiteBackend(http.Controller): @@ -19,9 +18,7 @@ class WebsiteBackend(http.Controller): 'website_designer': has_group_designer }, 'currency': request.env.company.currency_id.id, - 'dashboards': { - 'visits': {}, - } + 'dashboards': {} } current_website = website_id and Website.browse(website_id) or Website.get_current_website() @@ -33,40 +30,9 @@ class WebsiteBackend(http.Controller): website['selected'] = True if has_group_designer: - if current_website.google_management_client_id and current_website.google_analytics_key: - dashboard_data['dashboards']['visits'] = dict( - ga_client_id=current_website.google_management_client_id or '', - ga_analytics_key=current_website.google_analytics_key or '', - ) dashboard_data['dashboards']['plausible_share_url'] = current_website._get_plausible_share_url() return dashboard_data @http.route('/website/iframefallback', type="http", auth='user', website=True) def get_iframe_fallback(self): return request.render('website.iframefallback') - - @http.route('/website/dashboard/set_ga_data', type='json', auth='user') - def website_set_ga_data(self, website_id, ga_client_id, ga_analytics_key): - if not request.env.user.has_group('base.group_system'): - return { - 'error': { - 'title': _('Access Error'), - 'message': _('You do not have sufficient rights to perform that action.'), - } - } - if not ga_analytics_key or not ga_client_id.endswith('.apps.googleusercontent.com'): - return { - 'error': { - 'title': _('Incorrect Client ID / Key'), - 'message': _('The Google Analytics Client ID or Key you entered seems incorrect.'), - } - } - Website = request.env['website'] - current_website = website_id and Website.browse(website_id) or Website.get_current_website() - - request.env['res.config.settings'].create({ - 'google_management_client_id': ga_client_id, - 'google_analytics_key': ga_analytics_key, - 'website_id': current_website.id, - }).execute() - return True diff --git a/addons/website/models/res_config_settings.py b/addons/website/models/res_config_settings.py index 0f510bffe8f..1b4bed33d55 100644 --- a/addons/website/models/res_config_settings.py +++ b/addons/website/models/res_config_settings.py @@ -64,14 +64,6 @@ class ResConfigSettings(models.TransientModel): 'Google Analytics Key', related='website_id.google_analytics_key', readonly=False) - google_management_client_id = fields.Char( - 'Google Client ID', - related='website_id.google_management_client_id', - readonly=False) - google_management_client_secret = fields.Char( - 'Google Client Secret', - related='website_id.google_management_client_secret', - readonly=False) google_search_console = fields.Char( 'Google Search Console', related='website_id.google_search_console', @@ -115,10 +107,6 @@ class ResConfigSettings(models.TransientModel): "Google Analytics", compute='_compute_has_google_analytics', inverse='_inverse_has_google_analytics') - has_google_analytics_dashboard = fields.Boolean( - "Google Analytics Dashboard", - compute='_compute_has_google_analytics_dashboard', - inverse='_inverse_has_google_analytics_dashboard') has_google_search_console = fields.Boolean( "Console Google Search", compute='_compute_has_google_search_console', @@ -187,21 +175,8 @@ class ResConfigSettings(models.TransientModel): for config in self: if config.has_google_analytics: continue - config.has_google_analytics_dashboard = False config.google_analytics_key = False - @api.depends('website_id') - def _compute_has_google_analytics_dashboard(self): - for config in self: - config.has_google_analytics_dashboard = bool(config.google_management_client_id) - - def _inverse_has_google_analytics_dashboard(self): - for config in self: - if config.has_google_analytics_dashboard: - continue - config.google_management_client_id = False - config.google_management_client_secret = False - @api.depends('website_id') def _compute_has_google_search_console(self): for config in self: diff --git a/addons/website/models/website.py b/addons/website/models/website.py index f3267065e4e..85808bd844f 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -108,8 +108,6 @@ class Website(models.Model): has_social_default_image = fields.Boolean(compute='_compute_has_social_default_image', store=True) google_analytics_key = fields.Char('Google Analytics Key') - google_management_client_id = fields.Char('Google Client ID') - google_management_client_secret = fields.Char('Google Client Secret') google_search_console = fields.Char(help='Google key, or Enable to access first reply') google_maps_api_key = fields.Char('Google Maps API Key') diff --git a/addons/website/static/src/js/backend/dashboard.js b/addons/website/static/src/js/backend/dashboard.js index 8610a1374fa..b9b51aad3f1 100644 --- a/addons/website/static/src/js/backend/dashboard.js +++ b/addons/website/static/src/js/backend/dashboard.js @@ -1,18 +1,15 @@ -/* global google, gapi */ odoo.define('website.backend.dashboard', function (require) { 'use strict'; var AbstractAction = require('web.AbstractAction'); var ajax = require('web.ajax'); var core = require('web.core'); -var Dialog = require('web.Dialog'); var field_utils = require('web.field_utils'); var pyUtils = require('web.py_utils'); var session = require('web.session'); var time = require('web.time'); var web_client = require('web.web_client'); -var _t = core._t; var QWeb = core.qweb; var COLORS = ["#1f77b4", "#aec7e8"]; @@ -37,7 +34,6 @@ var Dashboard = AbstractAction.extend({ '/web/static/lib/Chart/Chart.js', ], events: { - 'click .js_link_analytics_settings': 'on_link_analytics_settings', 'click .o_dashboard_action': 'on_dashboard_action', 'click .o_dashboard_action_form': 'on_dashboard_action_form', }, @@ -105,59 +101,12 @@ var Dashboard = AbstractAction.extend({ return prom; }, - on_link_analytics_settings: function(ev) { - ev.preventDefault(); - - var self = this; - var dialog = new Dialog(this, { - size: 'medium', - title: _t('Connect Google Analytics'), - $content: QWeb.render('website.ga_dialog_content', { - ga_key: this.dashboards_data.visits.ga_client_id, - ga_analytics_key: this.dashboards_data.visits.ga_analytics_key, - }), - buttons: [ - { - text: _t("Save"), - classes: 'btn-primary', - close: true, - click: function() { - var ga_client_id = dialog.$el.find('input[name="ga_client_id"]').val(); - var ga_analytics_key = dialog.$el.find('input[name="ga_analytics_key"]').val(); - self.on_save_ga_client_id(ga_client_id, ga_analytics_key); - }, - }, - { - text: _t("Cancel"), - close: true, - }, - ], - }).open(); - }, - on_go_to_website: function (ev) { ev.preventDefault(); var website = _.findWhere(this.websites, {selected: true}); window.location.replace(`/web#action=website.website_preview&website_id=${website.id}`); }, - on_save_ga_client_id: function(ga_client_id, ga_analytics_key) { - var self = this; - return this._rpc({ - route: '/website/dashboard/set_ga_data', - params: { - 'website_id': self.website_id, - 'ga_client_id': ga_client_id, - 'ga_analytics_key': ga_analytics_key, - }, - }).then(function (result) { - if (result.error) { - self.displayNotification({ title: result.error.title, message: result.error.message, type: 'danger' }); - return; - } - self.on_date_range_button('week'); - }); - }, render_dashboards: function() { var self = this; @@ -268,46 +217,9 @@ var Dashboard = AbstractAction.extend({ self.render_graph('.o_graph_' + e.name, self.dashboards_data[e.name].graph, chart_id); } }); - this.render_graph_analytics(this.dashboards_data.visits.ga_client_id); } }, - render_graph_analytics: function(client_id) { - if (!this.dashboards_data.visits || !this.dashboards_data.visits.ga_client_id) { - return; - } - - this.load_analytics_api(); - - var $analytics_components = this.$('.js_analytics_components'); - this.addLoader($analytics_components); - - var self = this; - gapi.analytics.ready(function() { - - $analytics_components.empty(); - // 1. Authorize component - var $analytics_auth = $('
').addClass('col-lg-12'); - window.onOriginError = function () { - $analytics_components.find('.js_unauthorized_message').remove(); - self.display_unauthorized_message($analytics_components, 'not_initialized'); - }; - gapi.analytics.auth.authorize({ - container: $analytics_auth[0], - clientid: client_id - }); - - $analytics_auth.appendTo($analytics_components); - - self.handle_analytics_auth($analytics_components); - gapi.analytics.auth.on('signIn', function() { - delete window.onOriginError; - self.handle_analytics_auth($analytics_components); - }); - - }); - }, - on_date_range_button: function(date_range) { if (date_range === 'week') { this.date_range = 'week'; @@ -417,277 +329,7 @@ var Dashboard = AbstractAction.extend({ this.controlPanelProps.cp_content = { $searchview, $buttons }; }, - // Loads Analytics API - load_analytics_api: function() { - var self = this; - if (!("gapi" in window)) { - (function(w,d,s,g,js,fjs){ - g=w.gapi||(w.gapi={});g.analytics={q:[],ready:function(cb){this.q.push(cb);}}; - js=d.createElement(s);fjs=d.getElementsByTagName(s)[0]; - js.src='https://apis.google.com/js/platform.js'; - fjs.parentNode.insertBefore(js,fjs);js.onload=function(){g.load('analytics');}; - }(window,document,'script')); - gapi.analytics.ready(function() { - self.analytics_create_components(); - }); - } - }, - - handle_analytics_auth: function($analytics_components) { - $analytics_components.find('.js_unauthorized_message').remove(); - - // Check if the user is authenticated and has the right to make API calls - if (!gapi.analytics.auth.getAuthResponse()) { - this.display_unauthorized_message($analytics_components, 'not_connected'); - } else if (gapi.analytics.auth.getAuthResponse() && gapi.analytics.auth.getAuthResponse().scope.indexOf('https://www.googleapis.com/auth/analytics') === -1) { - this.display_unauthorized_message($analytics_components, 'no_right'); - } else { - this.make_analytics_calls($analytics_components); - } - }, - - display_unauthorized_message: function($analytics_components, reason) { - $analytics_components.prepend($(QWeb.render('website.unauthorized_analytics', {reason: reason}))); - }, - - make_analytics_calls: function($analytics_components) { - // 2. ActiveUsers component - var $analytics_users = $('
'); - var activeUsers = new gapi.analytics.ext.ActiveUsers({ - container: $analytics_users[0], - pollingInterval: 10, - }); - $analytics_users.appendTo($analytics_components); - - // 3. View Selector - var $analytics_view_selector = $('
').addClass('col-lg-12 o_properties_selection'); - var viewSelector = new gapi.analytics.ViewSelector({ - container: $analytics_view_selector[0], - }); - viewSelector.execute(); - $analytics_view_selector.appendTo($analytics_components); - - // 4. Chart graph - var start_date = '7daysAgo'; - if (this.date_range === 'month') { - start_date = '30daysAgo'; - } else if (this.date_range === 'year') { - start_date = '365daysAgo'; - } - var $analytics_chart_2 = $('
').addClass('col-lg-6 col-12'); - var breakdownChart = new gapi.analytics.googleCharts.DataChart({ - query: { - 'dimensions': 'ga:date', - 'metrics': 'ga:sessions', - 'start-date': start_date, - 'end-date': 'yesterday' - }, - chart: { - type: 'LINE', - container: $analytics_chart_2[0], - options: { - title: 'All', - width: '100%', - tooltip: {isHtml: true}, - } - } - }); - $analytics_chart_2.appendTo($analytics_components); - - // 5. Chart table - var $analytics_chart_1 = $('
').addClass('col-lg-6 col-12'); - var mainChart = new gapi.analytics.googleCharts.DataChart({ - query: { - 'dimensions': 'ga:medium', - 'metrics': 'ga:sessions', - 'sort': '-ga:sessions', - 'max-results': '6' - }, - chart: { - type: 'TABLE', - container: $analytics_chart_1[0], - options: { - width: '100%' - } - } - }); - $analytics_chart_1.appendTo($analytics_components); - - // Events handling & animations - - var table_row_listener; - - viewSelector.on('change', function(ids) { - var options = {query: {ids: ids}}; - activeUsers.set({ids: ids}).execute(); - mainChart.set(options).execute(); - breakdownChart.set(options).execute(); - - if (table_row_listener) { google.visualization.events.removeListener(table_row_listener); } - }); - - mainChart.on('success', function(response) { - var chart = response.chart; - var dataTable = response.dataTable; - - table_row_listener = google.visualization.events.addListener(chart, 'select', function() { - var options; - if (chart.getSelection().length) { - var row = chart.getSelection()[0].row; - var medium = dataTable.getValue(row, 0); - options = { - query: { - filters: 'ga:medium==' + medium, - }, - chart: { - options: { - title: medium, - } - } - }; - } else { - options = { - chart: { - options: { - title: 'All', - } - } - }; - delete breakdownChart.get().query.filters; - } - breakdownChart.set(options).execute(); - }); - }); - - // Add CSS animation to visually show the when users come and go. - activeUsers.once('success', function() { - var element = this.container.firstChild; - var timeout; - - this.on('change', function(data) { - element = this.container.firstChild; - var animationClass = data.delta > 0 ? 'is-increasing' : 'is-decreasing'; - element.className += (' ' + animationClass); - - clearTimeout(timeout); - timeout = setTimeout(function() { - element.className = element.className.replace(/ is-(increasing|decreasing)/g, ''); - }, 3000); - }); - }); - }, - - /* - * Credits to https://github.com/googleanalytics/ga-dev-tools - * This is the Active Users component that polls - * the number of active users on Analytics each 5 secs - */ - analytics_create_components: function() { - - gapi.analytics.createComponent('ActiveUsers', { - - initialize: function() { - this.activeUsers = 0; - gapi.analytics.auth.once('signOut', this.handleSignOut_.bind(this)); - }, - - execute: function() { - // Stop any polling currently going on. - if (this.polling_) { - this.stop(); - } - - this.render_(); - - // Wait until the user is authorized. - if (gapi.analytics.auth.isAuthorized()) { - this.pollActiveUsers_(); - } else { - gapi.analytics.auth.once('signIn', this.pollActiveUsers_.bind(this)); - } - }, - - stop: function() { - clearTimeout(this.timeout_); - this.polling_ = false; - this.emit('stop', {activeUsers: this.activeUsers}); - }, - - render_: function() { - var opts = this.get(); - - // Render the component inside the container. - this.container = typeof opts.container === 'string' ? - document.getElementById(opts.container) : opts.container; - - this.container.innerHTML = opts.template || this.template; - this.container.querySelector('b').innerHTML = this.activeUsers; - }, - - pollActiveUsers_: function() { - var options = this.get(); - var pollingInterval = (options.pollingInterval || 5) * 1000; - - if (isNaN(pollingInterval) || pollingInterval < 5000) { - throw new Error('Frequency must be 5 seconds or more.'); - } - - this.polling_ = true; - gapi.client.analytics.data.realtime - .get({ids:options.ids, metrics:'rt:activeUsers'}) - .then(function(response) { - var result = response.result; - var newValue = result.totalResults ? +result.rows[0][0] : 0; - var oldValue = this.activeUsers; - - this.emit('success', {activeUsers: this.activeUsers}); - - if (newValue !== oldValue) { - this.activeUsers = newValue; - this.onChange_(newValue - oldValue); - } - - if (this.polling_) { - this.timeout_ = setTimeout(this.pollActiveUsers_.bind(this), pollingInterval); - } - }.bind(this)); - }, - - onChange_: function(delta) { - var valueContainer = this.container.querySelector('b'); - if (valueContainer) { valueContainer.innerHTML = this.activeUsers; } - - this.emit('change', {activeUsers: this.activeUsers, delta: delta}); - if (delta > 0) { - this.emit('increase', {activeUsers: this.activeUsers, delta: delta}); - } else { - this.emit('decrease', {activeUsers: this.activeUsers, delta: delta}); - } - }, - - handleSignOut_: function() { - this.stop(); - gapi.analytics.auth.once('signIn', this.handleSignIn_.bind(this)); - }, - - handleSignIn_: function() { - this.pollActiveUsers_(); - gapi.analytics.auth.once('signOut', this.handleSignOut_.bind(this)); - }, - - template: - '
' + - 'Active Users: ' + - '
' - - }); - }, - // Utility functions - addLoader: function(selector) { - var loader = ''; - selector.html("
" + loader + "
"); - }, getValue: function(d) { return d[1]; }, format_number: function(value, type, digits, symbol) { if (type === 'currency') { diff --git a/addons/website/static/src/scss/website.backend.scss b/addons/website/static/src/scss/website.backend.scss index 55db5025d0e..86bc5b2b953 100644 --- a/addons/website/static/src/scss/website.backend.scss +++ b/addons/website/static/src/scss/website.backend.scss @@ -132,10 +132,6 @@ .o_buttons { position: relative; - - > button { - display: block; - } } .o_layer { @@ -147,61 +143,6 @@ height: 100%; } } - - .o_properties_selection { - - @include media-breakpoint-up(lg) { - display: flex; - } - - margin-top: 10px; - margin-bottom: 10px; - } - - .gapi-analytics-auth-styles-signinbutton { - cursor: pointer; - } - - .ActiveUsers { - position: relative; - float: right; - right: 10px; - border: 1px solid map-get($grays, '200'); - font-weight: 300; - white-space: nowrap; - padding: .5em 1.5em; - margin: .5em; - text-transform: uppercase; - } - - .ActiveUsers-value { - font-weight: 300; - margin-right: -.25em; - } - - .ActiveUsers.is-increasing { - animation: increase 3s; - } - - .ActiveUsers.is-decreasing { - animation: decrease 3s; - } - - @keyframes increase { - 10% { - background-color: lighten($o-brand-primary, 30%); - border-color: $o-brand-primary; - color: $o-brand-primary; - } - } - - @keyframes decrease { - 10% { - background-color: lighten($o-brand-primary, 30%); - border-color: $o-brand-primary; - color: $o-brand-primary; - } - } } tr.o_product_template { diff --git a/addons/website/static/src/xml/website.backend.xml b/addons/website/static/src/xml/website.backend.xml index b5453c35409..aeff11e7e0b 100644 --- a/addons/website/static/src/xml/website.backend.xml +++ b/addons/website/static/src/xml/website.backend.xml @@ -30,64 +30,34 @@
-
- + +
-

Visits

-
-
- Edit my Analytics Client ID +

Analytics

+
+
+