[REM] website_version: moved to enterprise

This commit is contained in:
Antony Lesuisse
2015-08-28 16:39:17 +02:00
parent 9f1cb9ed97
commit a11bab1226
67 changed files with 0 additions and 4461 deletions
-5
View File
@@ -1211,8 +1211,3 @@ source_lang = en
file_filter = addons/website_twitter/i18n/<lang>.po
source_file = addons/website_twitter/i18n/website_twitter.pot
source_lang = en
[odoo-9.website_version]
file_filter = addons/website_version/i18n/<lang>.po
source_file = addons/website_version/i18n/website_version.pot
source_lang = en
-6
View File
@@ -1,6 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import models
import controllers
import tests
-26
View File
@@ -1,26 +0,0 @@
{
'name': 'Website Versioning',
'category': 'Website',
'summary': 'Allow to save all the versions of your website and allow to perform AB testing.',
'version': '1.0',
'description': """
OpenERP Website CMS
===================
""",
'depends': ['website','marketing','google_account'],
'installable': True,
'data': [
'security/ir.model.access.csv',
'views/website_version_templates.xml',
'views/marketing_view.xml',
'views/website_version_views.xml',
'views/res_config.xml',
'data/data.xml',
],
'demo': [
'data/demo.xml',
],
'qweb': ['static/src/xml/*.xml'],
'application': False,
}
@@ -1,2 +0,0 @@
# -*- coding: utf-8 -*-
import main
-147
View File
@@ -1,147 +0,0 @@
# -*- coding: utf-8 -*-
import datetime
from openerp import http
from openerp.http import request
from openerp.addons.website.controllers.main import Website
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
GOOGLE_ANALYTICS_CONFIGURED = 2
GOOGLE_ANALYTICS_PARTIALLY_CONFIGURED = 1
GOOGLE_ANALYTICS_NOT_CONFIGURED = 0
class Versioning_Controller(Website):
@http.route('/website_version/change_version', type='json', auth="user", website=True)
def change_version(self, version_id):
request.session['version_id'] = version_id
return version_id
@http.route('/website_version/create_version', type='json', auth="user", website=True)
def create_version(self, name, version_id=None):
if not name:
name = datetime.datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
new_version = request.env['website_version.version'].create({'name': name, 'website_id': request.website.id})
if version_id:
request.env['website_version.version'].browse(version_id).copy_version(new_version.id)
request.session['version_id'] = new_version.id
return new_version.id
@http.route('/website_version/delete_version', type='json', auth="user", website=True)
def delete_version(self, version_id):
version = request.env['website_version.version'].browse(version_id)
name = version.name
version.unlink()
current_id = request.context.get('version_id')
if version_id == current_id:
request.session['version_id'] = 0
return name
@http.route('/website_version/check_version', type='json', auth="user", website=True)
def check_version(self, version_id):
#To check if the version is in a running or paused experiment
Exp = request.env['website_version.experiment']
return bool(Exp.search(['|', ('state', '=', 'running'), ('state', '=', 'paused'), ('experiment_version_ids.version_id', '=', version_id)], limit=1))
@http.route('/website_version/all_versions', type='json', auth="public", website=True)
def all_versions(self, view_id):
#To get all versions in the menu
view = request.env['ir.ui.view'].browse(view_id)
Version = request.env['website_version.version']
website_id = request.website.id
versions = Version.search([('website_id', '=', website_id), '|', ('view_ids.key', '=', view.key), ('view_ids.key', '=', 'website.footer_default')])
current_version_id = request.context.get('version_id')
check = False
result = []
for ver in versions:
if ver.id == current_version_id:
#To show in bold the current version in the menu
result.append({'id': ver.id, 'name': ver.name, 'bold': 1})
check = True
else:
result.append({'id': ver.id, 'name': ver.name, 'bold': 0})
#To always show in the menu the current version
if not check and current_version_id:
result.append({'id': current_version_id, 'name': Version.browse(current_version_id).name, 'bold': 1})
return result
@http.route('/website_version/has_experiments', type='json', auth="user", website=True)
def has_experiments(self, view_id):
v = request.env['ir.ui.view'].browse(view_id)
website_id = request.context.get('website_id')
return bool(request.env["website_version.experiment.version"].search([('version_id.view_ids.key', '=', v.key), ('experiment_id.website_id.id', '=', website_id)], limit=1))
@http.route('/website_version/publish_version', type='json', auth="user", website=True)
def publish_version(self, version_id, save_master, copy_master_name):
request.session['version_id'] = 0
return request.env['website_version.version'].browse(version_id).publish_version(save_master, copy_master_name)
@http.route('/website_version/diff_version', type='json', auth="user", website=True)
def diff_version(self, version_id):
mod_version = request.env['website_version.version']
version = mod_version.browse(version_id)
name_list = []
for view in version.view_ids:
name_list.append({'name': view.name, 'url': '/page/' + view.name.replace(' ', '').lower()})
return name_list
@http.route('/website_version/google_access', type='json', auth="user")
def google_authorize(self, **kw):
#Check if client_id and client_secret are set to get the authorization from Google
gs_obj = request.env['google.service']
gm_obj = request.env['google.management']
client_id = gs_obj.get_client_id('management', context=kw.get('local_context'))
client_secret = gs_obj.get_client_secret('management', context=kw.get('local_context'))
if not client_id or not client_secret:
dummy, action = request.registry.get('ir.model.data').get_object_reference(request.cr, request.uid, 'website_version', 'action_config_settings_google_management')
return {
"status": "need_config_from_admin",
"url": '',
"action": action
}
url = gm_obj.authorize_google_uri(from_url=kw.get('fromurl'), context=kw.get('local_context'))
return {
"status": "need_auth",
"url": url
}
@http.route('/website_version/set_google_access', type='json', auth="user", website=True)
def set_google_access(self, ga_key, view_id, client_id, client_secret):
#To set ga_key, view_id, client_id, client_secret
website_id = request.context.get('website_id')
web = request.env['website'].browse(website_id)
web.write({'google_analytics_key': ga_key.strip(), 'google_analytics_view_id': view_id.strip()})
if client_id and client_secret:
icp = request.env['ir.config_parameter']
icp.set_param('google_management_client_id', client_id.strip() or '', groups=['base.group_system'])
icp.set_param('google_management_client_secret', client_secret.strip() or '', groups=['base.group_system'])
@http.route('/website_version/all_versions_all_goals', type='json', auth="user", website=True)
def all_versions_all_goals(self, view_id):
#To get all versions and all goals to create an experiment
view = request.env['ir.ui.view']
version = request.env['website_version.version']
goal = request.env['website_version.goals']
icp = request.env['ir.config_parameter']
v = view.browse(view_id)
website_id = request.website.id
tab_version = version.search_read([('website_id', '=', website_id), '|', ('view_ids.key', '=', v.key), ('view_ids.key', '=', 'website.footer_default')], ['id', 'name'])
tab_goal = goal.search_read([], ['id', 'name'])
#Check if all the parameters are set to communicate with Google analytics
if icp.get_param('google_management_token'):
check_conf = GOOGLE_ANALYTICS_CONFIGURED
if request.website.google_analytics_key and request.website.google_analytics_view_id:
check_conf = GOOGLE_ANALYTICS_PARTIALLY_CONFIGURED
else:
check_conf = GOOGLE_ANALYTICS_NOT_CONFIGURED
return {'tab_version': tab_version, 'tab_goal': tab_goal, 'check_conf': check_conf}
@http.route('/website_version/launch_experiment', type='json', auth="user", website=True)
def launch_experiment(self, name, version_ids, goal_id):
existing_experiment = request.env['website_version.experiment'].check_no_overlap(version_ids)
if not existing_experiment['existing']:
vals = {'name': name, 'google_id': False, 'state': 'running', 'website_id': request.context.get('website_id'), 'experiment_version_ids': [[0, False, {'frequency': '50', 'version_id': int(version_ids[i]), 'google_index': i+1}] for i in range(len(version_ids))], 'goal_id': int(goal_id)}
exp_obj = request.env['website_version.experiment']
exp_obj.create(vals)
return existing_experiment
-21
View File
@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="goal_pageviews" model="website_version.goals">
<field name="name">Page Views</field>
<field name="google_ref">ga:pageviews</field>
</record>
<record id="goal_bounces" model="website_version.goals">
<field name="name">Decrease Bounces</field>
<field name="google_ref">ga:bounces</field>
</record>
<record id="goal_sessionDuration" model="website_version.goals">
<field name="name">Session Duration</field>
<field name="google_ref">ga:sessionDuration</field>
</record>
</data>
</openerp>
-158
View File
@@ -1,158 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="default_1" model="website_version.version">
<field name="name">Default_1</field>
<field name="website_id" ref="website.default_website"/>
</record>
<record id="default_2" model="website_version.version">
<field name="name">Default_2</field>
<field name="website_id" ref="website.website2"/>
</record>
<record id="version_localhost" model="website_version.version">
<field name="name">version localhost</field>
<field name="website_id" ref="website.default_website"/>
</record>
<record id="version_0_0_0_0" model="website_version.version">
<field name="name">version 0.0.0.0</field>
<field name="website_id" ref="website.website2"/>
</record>
<record id="website2_homepage_other" model="ir.ui.view">
<field name="name">Homepage</field>
<field name="type">qweb</field>
<field name="key">website.homepage</field>
<field name="version_id" ref="version_0_0_0_0"/>
<field name="website_id" ref="website.website2"/>
<field name="arch" type="xml">
<t name="Homepage" priority="29" t-name="website.homepage">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty">
<div class="carousel slide mb32" id="myCarousel0" style="height: 320px;">
<ol class="carousel-indicators hidden">
<li class="active" data-slide-to="0" data-target="#myCarousel0"/>
</ol>
<div class="carousel-inner">
<div class="item image_text oe_img_bg active" style="background-image: url(http://0.0.0.0:8069/website/static/src/img/banner/mountains.jpg);">
<div class="container">
<div class="row content">
<div class="carousel-content col-md-6 col-sm-12">
<h2>version 0.0.0.0</h2>
<h3>Click to customize this text</h3>
<p>
<a class="btn btn-success btn-large" href="/page/website.contactus">Contact us</a>
</p>
</div>
<span class="carousel-img col-md-6 hidden-sm hidden-xs"> </span>
</div>
</div>
</div>
</div>
<div class="carousel-control left hidden" data-slide="prev" data-target="#myCarousel0" href="#myCarousel0" style="width: 10%">
<i class="fa fa-chevron-left"/>
</div>
<div class="carousel-control right hidden" data-slide="next" data-target="#myCarousel0" href="#myCarousel0" style="width: 10%">
<i class="fa fa-chevron-right"/>
</div>
</div>
</div>
</t>
</t>
</field>
</record>
<record id="homepage_localhost" model="ir.ui.view">
<field name="name">Homepage</field>
<field name="type">qweb</field>
<field name="key">website.homepage</field>
<field name="version_id" ref="version_localhost"/>
<field name="website_id" ref="website.default_website"/>
<field name="arch" type="xml">
<t name="Homepage" priority="29" t-name="website.homepage">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty">
<div class="carousel slide mb32" id="myCarousel0" style="height: 320px;">
<ol class="carousel-indicators hidden">
<li class="active" data-slide-to="0" data-target="#myCarousel0"/>
</ol>
<div class="carousel-inner">
<div class="item image_text oe_img_bg active" style="background-image: url(http://localhost:8069/website/static/src/img/banner/greenfields.jpg);">
<div class="container">
<div class="row content">
<div class="carousel-content col-md-6 col-sm-12">
<h2>version localhost</h2>
<h3>Click to customize this text</h3>
<p>
<a class="btn btn-success btn-large" href="/page/website.contactus">Contact us</a>
</p>
</div>
<span class="carousel-img col-md-6 hidden-sm hidden-xs"> </span>
</div>
</div>
</div>
</div>
<div class="carousel-control left hidden" data-slide="prev" data-target="#myCarousel0" href="#myCarousel0" style="width: 10%">
<i class="fa fa-chevron-left"/>
</div>
<div class="carousel-control right hidden" data-slide="next" data-target="#myCarousel0" href="#myCarousel0" style="width: 10%">
<i class="fa fa-chevron-right"/>
</div>
</div>
</div>
</t>
</t>
</field>
</record>
<record id="homepage_default_2" model="ir.ui.view">
<field name="name">Homepage</field>
<field name="type">qweb</field>
<field name="key">website.homepage</field>
<field name="version_id" ref="default_2"/>
<field name="website_id" ref="website.website2"/>
<!-- <field name="application">Always applied</field> -->
<field name="arch" type="xml">
<t name="Homepage" priority="29" t-name="website.homepage">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty">
<div class="carousel slide mb32" id="myCarousel0" style="height: 320px;">
<ol class="carousel-indicators hidden">
<li class="active" data-slide-to="0" data-target="#myCarousel0"/>
</ol>
<div class="carousel-inner">
<div class="item image_text oe_img_bg active" style="background-image: url(http://localhost:8069/website/static/src/img/parallax/parallax_bg.jpg);">
<div class="container">
<div class="row content">
<div class="carousel-content col-md-6 col-sm-12">
<h2>Master</h2>
<h3>Click to customize this text</h3>
<p>
<a class="btn btn-success btn-large" href="/page/website.contactus">Contact us</a>
</p>
</div>
<span class="carousel-img col-md-6 hidden-sm hidden-xs">
<img alt="Banner Odoo Image" class="carousel-image img-responsive" src="/website/static/src/img/banner/banner_picture.png"/>
</span>
</div>
</div>
</div>
</div>
<div class="carousel-control left hidden" data-slide="prev" data-target="#myCarousel0" href="#myCarousel0" style="width: 10%">
<i class="fa fa-chevron-left"/>
</div>
<div class="carousel-control right hidden" data-slide="next" data-target="#myCarousel0" href="#myCarousel0" style="width: 10%">
<i class="fa fa-chevron-right"/>
</div>
</div>
</div>
</t>
</t>
</field>
</record>
</data>
</openerp>
File diff suppressed because it is too large Load Diff
@@ -1,8 +0,0 @@
import ir_ui_view
import version
import website
import experiment
import ir_qweb
import res_config
import ir_http
import google_management
-176
View File
@@ -1,176 +0,0 @@
# -*- coding: utf-8 -*-
from openerp.exceptions import Warning
from openerp import models, fields, api
from openerp.exceptions import ValidationError
from openerp.tools.translate import _
TOO_MUCH_EXPERIMENTS = 2
OVERLAP_EXPERIMENT = 1
CREATE_EXPERIMENT = 0
class Experiment_version(models.Model):
""" Allow to define the versions contained in an experiment.
The frequency is a ponderation to determine the probability to visit a version in an experiment.
The googe_index is the index of a version in an experiment, used to send data to Google Analytics.
"""
_name = "website_version.experiment.version"
_rec_name = "version_id"
version_id = fields.Many2one('website_version.version', string="Version", required=True, ondelete='cascade')
experiment_id = fields.Many2one('website_version.experiment', string="Experiment", required=True, ondelete='cascade')
frequency = fields.Selection([('10', 'Less'), ('50', 'Medium'), ('80', 'More')], string='Frequency', default='50')
google_index = fields.Integer(string='Google index')
class Goals(models.Model):
""" Allow to define the goal of an experiment.
The goals are defined in the Google Analytics account and can be synchronised in backend.
"""
_name = "website_version.goals"
name = fields.Char(string="Name", required=True)
google_ref = fields.Char(string="Google Reference", required=True)
class Experiment(models.Model):
"""An experiment pointed to some experiment_versions and dispatch each website visitor to a version.
"""
_name = "website_version.experiment"
_inherit = ['mail.thread']
_order = 'sequence'
@api.multi
@api.constrains('state')
def _check_view(self):
#No overlap for running experiments
for exp in self:
if exp.state == 'running':
for exp_ver in exp.experiment_version_ids:
if exp_ver.search([('version_id.view_ids.key', 'in', [v.key for v in exp_ver.version_id.view_ids]), ('experiment_id', '!=', exp_ver.experiment_id.id), ('experiment_id.website_id', '=', exp_ver.experiment_id.website_id.id), ('experiment_id.state', '=', 'running')]):
raise ValidationError('This experiment contains a view which is already used in another running experience')
return True
@api.multi
@api.constrains('website_id', 'experiment_version_ids')
def _check_website(self):
for exp in self:
for exp_ver in exp.experiment_version_ids:
if not exp_ver.version_id.website_id.id == exp.website_id.id:
raise ValidationError('This experiment must have versions which are in the same website')
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True):
""" Override read_group to always display all states. """
if groupby and groupby[0] == "state":
# Default result structure
# states = self._get_state_list(cr, uid, context=context)
states = [('running', 'Running'), ('paused', 'Paused'), ('ended', 'Ended')]
read_group_all_states = [{
'__context': {'group_by': groupby[1:]},
'__domain': domain + [('state', '=', state_value)],
'state': state_value,
'state_count': 0,
} for state_value, state_name in states]
# Get standard results
read_group_res = super(Experiment, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
# Update standard results with default results
result = []
for state_value, state_name in states:
res = filter(lambda x: x['state'] == state_value, read_group_res)
if not res:
res = filter(lambda x: x['state'] == state_value, read_group_all_states)
res[0]['state'] = [state_value, state_name]
result.append(res[0])
return result
else:
return super(Experiment, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
@api.one
def _get_version_number(self):
for exp in self:
exp.version_number = len(exp.experiment_version_ids) + 1
name = fields.Char(string="Title", required=True)
experiment_version_ids = fields.One2many('website_version.experiment.version', 'experiment_id', string="Experiment Version")
website_id = fields.Many2one('website', string="Website", required=True)
state = fields.Selection([('running', 'Running'), ('paused', 'Paused'), ('ended', 'Ended')], 'Status', required=True, copy=False, track_visibility='onchange', default='running')
goal_id = fields.Many2one('website_version.goals', string="Objective", required=True)
color = fields.Integer('Color Index')
version_number = fields.Integer(compute=_get_version_number, string='Version Number')
sequence = fields.Integer('Sequence', required=True, default=1)
google_id = fields.Char(string="Google id")
@api.model
def create(self, vals):
exp = {
'name': vals['name'],
'objectiveMetric': self.env['website_version.goals'].browse([vals['goal_id']])[0].google_ref,
'status': vals['state'],
'variations': [{'name': 'master', 'url': 'http://localhost/master'}]
}
version_list = vals.get('experiment_version_ids', [])
for version in version_list:
if version[0] == 0:
name = self.env['website_version.version'].browse([version[2]['version_id']])[0].name
#We must give a URL for each version in the experiment
exp['variations'].append({'name': name, 'url': 'http://localhost/' + name})
else:
raise Warning(_("The experiment you try to create has a bad format."))
if not version_list:
raise Warning(_("You must select at least one version in your experiment."))
vals['google_id'] = self.env['google.management'].create_an_experiment(exp, vals['website_id'])
return super(Experiment, self).create(vals)
@api.multi
def write(self, vals):
state = vals.get('state')
for exp in self:
if state and exp.state == 'ended':
raise Warning(_("You cannot modify an ended experiment."))
elif state == 'ended':
#google_data is the data to send to Googe
google_data = {
'name': exp.name,
'status': state,
'variations': [{'name': 'master', 'url': 'http://localhost/master'}],
}
for exp_v in exp.experiment_version_ids:
google_data['variations'].append({'name': exp_v.version_id.name, 'url': 'http://localhost/'+exp_v.version_id.name})
#to check the constraints before to write on the google analytics account
self.env['google.management'].update_an_experiment(google_data, exp.google_id, exp.website_id.id)
return super(Experiment, self).write(vals)
@api.multi
def unlink(self):
for exp in self:
self.env['google.management'].delete_an_experiment(exp.google_id, exp.website_id.id)
return super(Experiment, self).unlink()
@api.multi
def update_goals(self):
gm_obj = self.env['google.management']
goals_obj = self.env['website_version.goals']
website_id = self.env.context.get('website_id')
if not website_id:
raise Warning("You must specify the website.")
for goal in gm_obj.get_goal_info(website_id)[1]['items']:
if not goals_obj.search([('name', '=', goal['name'])]):
vals = {'name': goal['name'], 'google_ref': 'ga:goal' + goal['id'] + 'Completions'}
goals_obj.create(vals)
def check_no_overlap(self, version_ids):
if self.search_count(['|', ('state', '=', 'running'), ('state', '=', 'paused')]) >= 24:
return {'existing': TOO_MUCH_EXPERIMENTS, 'name': ""}
#Check if version_ids don't overlap with running experiments and return the name of the experiment if there 's an overlap
version_keys = set([v['key'] for v in self.env['ir.ui.view'].search_read([('version_id', 'in', version_ids)], ['key'])])
exp_mod = self.env['website_version.experiment']
exps = exp_mod.search([('state', '=', 'running'), ('website_id', '=', self.env.context.get('website_id'))])
for exp in exps:
for exp_ver in exp.experiment_version_ids:
for view in exp_ver.version_id.view_ids:
if view.key in version_keys:
return {'existing': OVERLAP_EXPERIMENT, 'name': exp.name}
return {'existing': CREATE_EXPERIMENT, 'name': ""}
@@ -1,157 +0,0 @@
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
import logging
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
from openerp.exceptions import Warning
from openerp import models, exceptions, api
from openerp.tools.translate import _
import simplejson
_logger = logging.getLogger(__name__)
class google_management(models.AbstractModel):
STR_SERVICE = 'management'
_name = 'google.%s' % STR_SERVICE
@api.model
def generate_data(self, experiment, isCreating=False):
return {
'name': experiment['name'],
'status': experiment['status'],
'variations': experiment['variations']
}
@api.model
def create_an_experiment(self, data, website_id):
gs_pool = self.env['google.service']
website = self.env['website'].browse(website_id)[0]
webPropertyId = website.google_analytics_key
action_id = self.env['ir.model.data'].xmlid_to_res_id('website_version.action_website_view')
if not webPropertyId:
raise exceptions.RedirectWarning('Click on the website you want to make A/B testing and configure the Google Analytics Key and View ID', action_id, 'go to the websites menu')
accountId = webPropertyId.split('-')[1]
profileId = website.google_analytics_view_id
if not profileId:
raise exceptions.RedirectWarning('Click on the website you want to make A/B testing and configure the Google Analytics Key and View ID', action_id, 'go to the websites menu')
url = '/analytics/v3/management/accounts/%s/webproperties/%s/profiles/%s/experiments?access_token=%s' % (accountId, webPropertyId, profileId, self.get_token())
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
data_json = simplejson.dumps(data)
try:
x = gs_pool._do_request(url, data_json, headers, type='POST')
result = x[1]['id']
except Exception, e:
_logger.info(_('An exception occured during the google analytics rquest: %s') % e)
raise
return result
@api.model
def update_an_experiment(self, data, google_id, website_id):
gs_pool = self.env['google.service']
website = self.env['website'].browse(website_id)[0]
webPropertyId = website.google_analytics_key
accountId = webPropertyId.split('-')[1]
profileId = website.google_analytics_view_id
url = '/analytics/v3/management/accounts/%s/webproperties/%s/profiles/%s/experiments/%s?access_token=%s' % (accountId, webPropertyId, profileId, google_id, self.get_token())
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
data_json = simplejson.dumps(data)
return gs_pool._do_request(url, data_json, headers, type='PUT')
@api.model
def get_experiment_info(self, google_id, website_id):
gs_pool = self.env['google.service']
website = self.env['website'].browse(website_id)[0]
webPropertyId = website.google_analytics_key
accountId = webPropertyId.split('-')[1]
profileId = website.google_analytics_view_id
params = {
'access_token': self.get_token(),
}
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
url = '/analytics/v3/management/accounts/%s/webproperties/%s/profiles/%s/experiments/%s' % (accountId, webPropertyId, profileId, google_id)
return gs_pool._do_request(url, params, headers, type='GET')
@api.model
def get_goal_info(self, website_id):
gs_pool = self.env['google.service']
website = self.env['website'].browse(website_id)[0]
webPropertyId = website.google_analytics_key
accountId = webPropertyId.split('-')[1]
profileId = website.google_analytics_view_id
params = {
'access_token': self.get_token(),
}
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
url = '/analytics/v3/management/accounts/%s/webproperties/%s/profiles/%s/goals' % (accountId, webPropertyId, profileId)
return gs_pool._do_request(url, params, headers, type='GET')
@api.model
def delete_an_experiment(self, google_id, website_id):
gs_pool = self.env['google.service']
website = self.env['website'].browse(website_id)[0]
webPropertyId = website.google_analytics_key
accountId = webPropertyId.split('-')[1]
profileId = website.google_analytics_view_id
params = {
'access_token': self.get_token()
}
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
url = '/analytics/v3/management/accounts/%s/webproperties/%s/profiles/%s/experiments/%s' % (accountId, webPropertyId, profileId, google_id)
return gs_pool._do_request(url, params, headers, type='DELETE')
@api.model
def get_token(self):
icp = self.env['ir.config_parameter'].sudo()
validity = icp.get_param('google_%s_token_validity' % self.STR_SERVICE)
token = icp.get_param('google_%s_token' % self.STR_SERVICE)
if not (validity and token):
raise Warning(_("You must configure your account."))
if datetime.strptime(validity.split('.')[0], DEFAULT_SERVER_DATETIME_FORMAT) < (datetime.now() + timedelta(minutes=3)):
token = self.do_refresh_token()
return token
@api.model
def do_refresh_token(self):
gs_pool = self.env['google.service']
icp = self.env['ir.config_parameter'].sudo()
rtoken = icp.get_param('google_%s_rtoken' % self.STR_SERVICE)
all_token = gs_pool._refresh_google_token_json(rtoken, self.STR_SERVICE)
icp.set_param('google_%s_token_validity' % self.STR_SERVICE, datetime.now() + timedelta(seconds=all_token.get('expires_in')))
icp.set_param('google_%s_token' % self.STR_SERVICE, all_token.get('access_token'))
return all_token.get('access_token')
# Should be called at configuration
def get_management_scope(self):
return 'https://www.googleapis.com/auth/analytics https://www.googleapis.com/auth/analytics.edit'
@api.model
def authorize_google_uri(self, from_url='http://www.odoo.com', context=None):
url = self.pool['google.service']._get_authorize_uri(self.env.cr, self.env.uid, from_url, self.STR_SERVICE, scope=self.get_management_scope(), context=self.env.context)
return url
# convert code from authorize into token
@api.model
def set_all_tokens(self, authorization_code):
gs_pool = self.env['google.service']
all_token = gs_pool._get_google_token_json(authorization_code, self.STR_SERVICE)
vals = {}
vals['google_%s_rtoken' % self.STR_SERVICE] = all_token.get('refresh_token')
vals['google_%s_token_validity' % self.STR_SERVICE] = datetime.now() + timedelta(seconds=all_token.get('expires_in'))
vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token')
icp = self.env['ir.config_parameter'].sudo()
icp.set_param('google_%s_rtoken' % self.STR_SERVICE, all_token.get('refresh_token'))
icp.set_param('google_%s_token_validity' % self.STR_SERVICE, datetime.now() + timedelta(seconds=all_token.get('expires_in')))
icp.set_param('google_%s_token' % self.STR_SERVICE, all_token.get('access_token'))
-16
View File
@@ -1,16 +0,0 @@
# -*- coding: utf-8 -*-
from openerp.http import request
from openerp.osv import orm
import json
class ir_http(orm.AbstractModel):
_inherit = 'ir.http'
def _dispatch(self):
x = super(ir_http, self)._dispatch()
if request.context.get('website_version_experiment'):
data=json.dumps(request.context['website_version_experiment'], ensure_ascii=False)
x.set_cookie('website_version_experiment', data)
return x
-43
View File
@@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
"""
Website-context rendering needs to add some metadata to rendered fields,
as well as render a few fields differently.
Also, adds methods to convert values back to openerp models.
"""
from openerp import models
class QWeb(models.AbstractModel):
""" QWeb object for rendering stuff in the website context
"""
_inherit = 'ir.qweb'
def render(self, cr, uid, id_or_xml_id, qwebcontext=None, loader=None, context=None):
if context is None:
context = {}
website_id = context.get('website_id')
if website_id:
if 'experiment_id' in context:
#Is there a version which have the view.key == id_or_xml_id and which is in a running experiment?
exp_ver_id = self.pool["website_version.experiment.version"].search(cr, uid, [('version_id.view_ids.key', '=', id_or_xml_id), ('experiment_id.state', '=', 'running'), ('experiment_id.website_id.id', '=', website_id)], context=context)
if exp_ver_id:
#If yes take the first because there is no overlap between running experiments.
exp_version = self.pool["website_version.experiment.version"].browse(cr, uid, [exp_ver_id[0]], context=context)
exp = exp_version.experiment_id
#We set the google_id as key in the dictionnary to avoid problem when reinitializating the db, exp.google_id is unique
version_id = context.get('website_version_experiment').get(str(exp.google_id))
if version_id:
context['version_id'] = int(version_id)
if isinstance(id_or_xml_id, (int, long)):
id_or_xml_id = self.pool["ir.ui.view"].browse(cr, uid, id_or_xml_id, context=context).key
domain = [('key', '=', id_or_xml_id), '|', ('website_id', '=', website_id), ('website_id', '=', False)]
version_id = context.get('version_id')
domain += version_id and ['|', ('version_id', '=', False), ('version_id', '=', version_id)] or [('version_id', '=', False)]
id_or_xml_id = self.pool["ir.ui.view"].search(cr, uid, domain, order='website_id, version_id', limit=1, context=context)[0]
return super(QWeb, self).render(cr, uid, id_or_xml_id, qwebcontext, loader=loader, context=context)
-160
View File
@@ -1,160 +0,0 @@
# -*- coding: utf-8 -*-
from lxml import etree
from openerp import tools, fields, models, api
class view(models.Model):
_inherit = "ir.ui.view"
version_id = fields.Many2one('website_version.version', ondelete='cascade', string="Version")
@api.multi
def write(self, vals):
if self.env.context is None:
self.env.context = {}
version_id = self.env.context.get('version_id')
#If you write on a shared view, your modifications will be seen on every website wich uses these view.
#To dedicate a view for a specific website, you must create a version and publish these version.
if version_id and not self.env.context.get('write_on_view') and not 'active' in vals:
self.env.context = dict(self.env.context, write_on_view=True)
version = self.env['website_version.version'].browse(version_id)
website_id = version.website_id.id
version_view_ids = self.env['ir.ui.view']
for current in self:
#check if current is in version
if current.version_id.id == version_id:
version_view_ids += current
else:
new_v = self.search([('website_id', '=', website_id), ('version_id', '=', version_id), ('key', '=', current.key)])
if new_v:
version_view_ids += new_v
else:
copy_v = current.copy({'version_id': version_id, 'website_id': website_id})
version_view_ids += copy_v
super(view, version_view_ids).write(vals)
else:
self.env.context = dict(self.env.context, write_on_view=True)
super(view, self).write(vals)
@api.one
def publish(self):
#To delete and replace views which are in the website( in fact with website_id)
master_record = self.search([('key', '=', self.key), ('version_id', '=', False), ('website_id', '=', self.website_id.id)])
if master_record:
master_record.unlink()
self.copy({'version_id': None})
#To publish a view in backend
@api.multi
def action_publish(self):
self.publish()
@api.model
def get_view_id(self, xml_id):
if self.env.context and 'website_id' in self.env.context and not isinstance(xml_id, (int, long)):
domain = [('key', '=', xml_id), '|', ('website_id', '=', self.env.context['website_id']), ('website_id', '=', False)]
if 'version_id' in self.env.context:
domain += ['|', ('version_id', '=', self.env.context['version_id']), ('version_id', '=', False)]
xml_id = self.search(domain, order='website_id,version_id', limit=1).id
else:
xml_id = super(view, self).get_view_id(xml_id)
return xml_id
@tools.ormcache_context('uid', 'view_id',
keys=('lang', 'inherit_branding', 'editable', 'translatable', 'edit_translations', 'website_id', 'version_id'))
def _read_template(self, cr, uid, view_id, context=None):
arch = self.read_combined(cr, uid, view_id, fields=['arch'], context=context)['arch']
arch_tree = etree.fromstring(arch)
if 'lang' in context:
arch_tree = self.translate_qweb(cr, uid, view_id, arch_tree, context['lang'], context)
self.distribute_branding(arch_tree)
root = etree.Element('templates')
root.append(arch_tree)
arch = etree.tostring(root, encoding='utf-8', xml_declaration=True)
return arch
#To take the right inheriting views
@api.model
def get_inheriting_views_arch(self, view_id, model):
arch = super(view, self).get_inheriting_views_arch(view_id, model)
vw = self.browse(view_id)
if not (self.env.context and self.env.context.get('website_id') and vw.type == 'qweb'):
return arch
#right_ids to collect the right ids according to the key
right_ids = {}
priority = {}
#To create a dico called view_arch where v(key) is the id and a the arch(value)
view_arch = dict([(v, a) for a, v in arch])
keys = self.browse(view_arch.keys())
#The view to take depends of the context
context_version_id = self.env.context.get('version_id')
context_website_id = self.env.context.get('website_id')
for k in keys:
#priority:1(with context_version_id) take the view which is in the same version
if context_version_id and k.version_id.id and k.version_id.id == context_version_id:
right_ids[k.key] = k.id
priority[k.key] = 3
#priority:2(context_version_id) take the view which is just in the same website
elif context_version_id and k.version_id.id is False and k.website_id.id and k.website_id.id == context_website_id:
if not priority.get(k.key) or priority.get(k.key) < 3:
right_ids[k.key] = k.id
priority[k.key] = 2
#priority:3(context_version_id) take the original view
elif context_version_id and k.version_id.id is False and k.website_id.id is False:
if not priority.get(k.key) or priority.get(k.key) < 2:
right_ids[k.key] = k.id
priority[k.key] = 1
#priority:1(without context_version_id) take the view which is just in the same website
elif not context_version_id and k.version_id.id is False and k.website_id.id and k.website_id.id == context_website_id:
right_ids[k.key] = k.id
priority[k.key] = 2
#priority:2(without context_version_id) take the original view
elif not context_version_id and k.version_id.id is False and k.website_id.id is False:
if not priority.get(k.key) or priority.get(k.key) < 2:
right_ids[k.key] = k.id
priority[k.key] = 1
return [x for x in arch if x[1] in right_ids.values()]
#To active or desactive the right views according to the key
def toggle(self, cr, uid, ids, context=None):
""" Switches between enabled and disabled statuses
"""
for view in self.browse(cr, uid, ids, context=dict(context or {}, active_test=False)):
all_id = self.search(cr, uid, [('key', '=', view.key)], context=dict(context or {}, active_test=False))
for v in self.browse(cr, uid, all_id, context=dict(context or {}, active_test=False)):
v.write({'active': not v.active})
@api.model
def translate_qweb(self, id_, arch, lang):
view = self.browse(id_)
if not view.key:
return super(view, self).translate_qweb(id_, arch, lang)
views = self.search([('key', '=', view.key), '|',
('website_id', '=', view.website_id.id), ('website_id', '=', False)])
fallback_views = self
for v in views:
if v.mode == 'primary' and v.inherit_id.mode == 'primary':
# template is `cloned` from parent view
fallback_views += view.inherit_id
views += fallback_views
def translate_func(term):
Translations = self.env['ir.translation']
trans = Translations._get_source('website', 'view', lang, term, views.ids)
return trans
self._translate_qweb(arch, translate_func)
return arch
@api.model
def customize_template_get(self, key, full=False, bundles=False, **kw):
result = super(view, self).customize_template_get(key, full=full, bundles=bundles, **kw)
check = []
res = []
for data in result:
if data['name'] not in check:
check.append(data['name'])
res.append(data)
return res
@@ -1,25 +0,0 @@
from openerp import fields, models, api
class analytics_config_settings(models.TransientModel):
_inherit = 'base.config.settings'
ga_sync = fields.Boolean("Show tutorial to know how to get my 'Client ID' and my 'Client Secret'")
ga_client_id = fields.Char('Client ID')
ga_client_secret = fields.Char('Client Secret')
google_management_authorization = fields.Char('Google authorization')
@api.model
def set_analytics(self, ids):
params = self.env['ir.config_parameter']
myself = self.browse(ids[0])
params.set_param('google_management_client_id', myself.ga_client_id or '', groups=['base.group_system'])
params.set_param('google_management_client_secret', myself.ga_client_secret or '', groups=['base.group_system'])
@api.model
def get_analytics(self, ids):
params = self.env.get('ir.config_parameter')
ga_client_id = params.get_param('google_management_client_id', default='')
ga_client_secret = params.get_param('google_management_client_secret', default='')
return dict(ga_client_id=ga_client_id, ga_client_secret=ga_client_secret)
-74
View File
@@ -1,74 +0,0 @@
# -*- coding: utf-8 -*-
from openerp import fields, models, api
from openerp.exceptions import Warning
from openerp.http import request
from openerp.tools.translate import _
class version(models.Model):
""" A version is a set of qweb views which differs from the qweb views in production for the website.
"""
_name = "website_version.version"
name = fields.Char(string="Title", required=True)
view_ids = fields.One2many('ir.ui.view', 'version_id', string="View", copy=True)
website_id = fields.Many2one('website', ondelete='cascade', string="Website")
create_date = fields.Datetime('Create Date')
_sql_constraints = [
('name_uniq', 'unique(name, website_id)', _('You cannot have multiple versions with the same name in the same domain!')),
]
@api.multi
def unlink(self):
for id in self.ids:
result = self.env['website_version.experiment'].search(['|', ('state', '=', 'running'), ('state', '=', 'paused'), ('experiment_version_ids.version_id', '=', id)])
if result:
raise Warning(_("You cannot delete a version which is in a running or paused experiment."))
#To avoid problem when we delete versions in Backend
if request:
request.session['version_id'] = 0
return super(version, self).unlink()
@api.multi
def action_publish(self):
for version in self:
self.view_ids.publish()
@api.one
def publish_version(self, save_master, copy_master_name):
del_l = self.env['ir.ui.view']
copy_l = self.env['ir.ui.view']
ir_ui_view = self.env['ir.ui.view']
for view in self.view_ids:
master_id = ir_ui_view .search([('key', '=', view.key), ('version_id', '=', False), ('website_id', '=', view.website_id.id)])
if master_id:
#Delete all the website views having a key which is in the version published
del_l += master_id
copy_l += master_id
else:
#Views that have no website_id, must be copied because they can be shared with another website
master_id = ir_ui_view.search([('key', '=', view.key), ('version_id', '=', False), ('website_id', '=', False)])
copy_l += master_id
if copy_l:
if save_master:
#To check if the name of the version to copy master already exists
check_id = self.search([('name', '=', copy_master_name), ('website_id', '=', self.website_id.id)])
#If it already exists, we delete the old to make the new
if check_id:
check_id.unlink()
copy_version_id = self.create({'name': copy_master_name, 'website_id': self.website_id.id})
copy_l.copy({'version_id': copy_version_id.id, 'website_id': self.website_id.id})
del_l.unlink()
#All the views in the version published are copied without version_id
for view in self.view_ids:
view.copy({'version_id': None})
return self.name
#To make a version of a version
@api.one
def copy_version(self, new_version_id):
for view in self.view_ids:
view.copy({'version_id': new_version_id})
-83
View File
@@ -1,83 +0,0 @@
# -*- coding: utf-8 -*-
import json
from openerp import fields, models, api
from openerp.http import request
import random
class NewWebsite(models.Model):
_inherit = "website"
tuto_google_analytics = fields.Boolean("How to get GA key and View ID")
google_analytics_view_id = fields.Char('View ID')
google_management_authorization = fields.Char('Google authorization')
@api.model
def get_current_version(self, context=None):
Version = request.env['website_version.version']
version_id = request.context.get('version_id')
if not version_id:
request.context['version_id'] = 0
return (0, '')
return (version_id, Version.browse(version_id).name)
@api.model
def get_current_website(self):
website = super(NewWebsite, self).get_current_website()
#We just set the cookie for the first visit
if 'website_version_experiment' in request.httprequest.cookies:
EXP = json.loads(request.httprequest.cookies.get('website_version_experiment'))
else:
EXP = request.context.get('website_version_experiment', {})
exps = self.env["website_version.experiment"].search([('state', '=', 'running'), ('website_id.id', '=', website.id), ('google_id', 'not in', EXP.keys())])
for exp in exps:
result = []
pond_sum = 0
for exp_snap in exp.experiment_version_ids:
result.append([int(exp_snap.frequency)+pond_sum, exp_snap.version_id.id])
pond_sum += int(exp_snap.frequency)
if pond_sum:
#by default master has a frequency of 50
pond_sum = pond_sum + 50
#by default on master
#We set the google_id as key in the cookie to avoid problem when reinitializating the db
EXP[exp.google_id] = str(0)
x = random.randint(0, pond_sum-1)
for res in result:
if x < res[0]:
EXP[exp.google_id] = str(res[1])
break
request.context['website_version_experiment'] = EXP
request.context['website_id'] = website.id
if 'version_id' in request.session:
request.context['version_id'] = request.session.get('version_id')
elif self.env['res.users'].has_group('base.group_website_publisher'):
request.context['version_id'] = 0
else:
request.context['experiment_id'] = 1
return website
@api.model
def google_analytics_data(self, main_object):
#To get the ExpId and the VarId of the view if it is in a running experiment
result = {}
if main_object and main_object._name == 'ir.ui.view':
view = main_object
#search all the running experiments with the key of view
exp_ids = self.env['website_version.experiment'].search([('experiment_version_ids.version_id.view_ids.key', '=', view.key), ('state', '=', 'running'), ('experiment_version_ids.version_id.website_id', '=', self.env.context.get('website_id'))])
if exp_ids:
#No overlap between running experiments then we can take the first one
result['expId'] = exp_ids[0].google_id
version_id = self.env.context.get('version_id') or self.env.context['website_version_experiment'].get(exp_ids[0].google_id)
if version_id:
exp_ver_ids = self.env['website_version.experiment.version'].search([('experiment_id', '=', exp_ids[0].id), ('version_id', '=', int(version_id))], limit=1)
if exp_ver_ids:
result['expVar'] = exp_ver_ids[0].google_index
else:
result['expVar'] = 0
return result
@@ -1,6 +0,0 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_website_version_version,access_website_version_version,model_website_version_version,,1,0,0,0
access_website_version_version_admin,access_website_version_version_admin,model_website_version_version,base.group_website_designer,1,1,1,1
access_website_version_experiment,access_website_version_experiment,model_website_version_experiment,,1,1,1,1
access_website_version_experiment_version,access_website_version_experiment_version,model_website_version_experiment_version,,1,1,1,1
access_website_version_goals,access_website_version_goals,model_website_version_goals,,1,1,1,1
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 access_website_version_version access_website_version_version model_website_version_version 1 0 0 0
3 access_website_version_version_admin access_website_version_version_admin model_website_version_version base.group_website_designer 1 1 1 1
4 access_website_version_experiment access_website_version_experiment model_website_version_experiment 1 1 1 1
5 access_website_version_experiment_version access_website_version_experiment_version model_website_version_experiment_version 1 1 1 1
6 access_website_version_goals access_website_version_goals model_website_version_goals 1 1 1 1
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

@@ -1,48 +0,0 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan">Website Versioning</h2>
<h3 class="oe_slogan">Save all the versions of your website with Website Versioning</h3>
<div class="oe_span6">
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="presentation.png">
</div>
</div>
<div class="oe_span6">
<p class="oe_mt32">
Never loss any data on your website when you are editing pages. With Website Versioning you can save all the modification you realised and retrieve all of them through the versions.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<div class="oe_span12">
<h2 class="oe_slogan">Features</h2>
<p class="oe_mt32">
Quickly create different versions of your website, organize all versions with date or name and update all your website in just one click.
</p>
</div>
<div class="oe_span4">
<h3>Save a modification as a draft version</h3>
<p>
People used to modify their website instinctively. Sometimes it is great but sometimes it is also bad. With Website Versioning, delete the bad and save the great through versions.
</p>
</div>
<div class="oe_span4">
<h3>Publish a draft version you like</h3>
<p>
When you decide that a version seems to be the good one to illustrate your website, you can simply publish this version in one click.
</p>
</div>
<div class="oe_span4">
<h3>Travel in the past</h3>
<p>
With Website Versioning, you can easily retrieve your old versions thanks to their name. Just choose the right one to begin the edition of a new great version.
</p>
</div>
</div>
</section>
<section class="oe_container oe_separator">
</section>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 KiB

@@ -1,7 +0,0 @@
@charset "utf-8";
img.analytics_img_tuto {
margin-left : 50px;
margin-bottom : 10px;
border: 2px solid grey;
}
@@ -1,16 +0,0 @@
.dropdown-menu .o_version > a:after {
margin-right: 10px;
}
.navbar-inverse .btn-link.o_version:hover {
color: #000;
}
.btn.o_version {
text-align: left;
}
.o_required_field{
background-color: #d2d2ff;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

@@ -1,90 +0,0 @@
odoo.define('website_version.edit', function (require) {
'use strict';
var ajax = require('web.ajax');
var core = require('web.core');
var base = require('web_editor.base');
var editor = require('web_editor.editor');
var _t = core._t;
var qweb = core.qweb;
editor.Class.include({
start: function() {
var self = this;
this.$el.on('click', '#save_as_new_version', function() {
var wizardA = $(qweb.render("website_version.new_version",{'default_name': moment().format('L')}));
wizardA.appendTo($('body')).modal({"keyboard" :true});
wizardA.on('click','.o_create', function(){
wizardA.find('.o_message').remove();
var version_name = wizardA.find('.o_version_name').val();
if(version_name.length == 0){
wizardA.find(".o_version_name").after("<p class='o_message' style='color : red'> *"+_t("This field is required")+"</p>");
}
else{
wizardA.modal("hide");
ajax.jsonRpc( '/website_version/create_version', 'call', { 'name': version_name, 'version_id': 0}).then(function (result) {
$('html').data('version_id', result);
var wizard = $(qweb.render("website_version.dialogue",{message:_.str.sprintf("You are now working on version: %s.", version_name),
dialogue:_.str.sprintf("If you edit this page or others, all changes will be recorded in the version. It will not be visible by visitors until you publish the version.")}));
wizard.appendTo($('body')).modal({"keyboard" :true});
wizard.on('click','.o_confirm', function(){
self.save();
});
wizard.on('hidden.bs.modal', function () {$(this).remove();});
}).fail(function(){
var wizard = $(qweb.render("website_version.message",{message:_t("This name already exists.")}));
wizard.appendTo($('body')).modal({"keyboard" :true});
wizard.on('hidden.bs.modal', function () {$(this).remove();});
});
}
});
wizardA.on('hidden.bs.modal', function () {$(this).remove();});
});
var ver_name = $('#version-menu-button').data('version_name');
if(ver_name){
this.$el.find('button[data-action="save"]').text(_.str.sprintf(_t("Save on %s"), ver_name));
}
this.$el.on('click', '#save_and_publish', function() {
var version_id = base.get_context().version_id;
if(version_id)
{
self.save();
}
else
{
var wizard = $(qweb.render("website_version.publish",{message:_t("Are you sure you want to publish your modifications.")}));
wizard.appendTo($('body')).modal({"keyboard" :true});
wizard.on('click','.o_confirm', function(){
self.save();
});
wizard.on('hidden.bs.modal', function () {$(this).remove();});
}
});
$('.option_choice').click(function() {
self.$el.find(".o_second_choice").remove();
var name = $('#version-menu-button').data('version_name');
if(name){
self.$el.find(".o_first_choice").before(qweb.render("website_version.all_options", {version:'Save on '+name}));
}
else{
self.$el.find(".o_first_choice").before(qweb.render("website_version.all_options", {version:'Save and Publish'}));
}
});
this.$('button[data-action=save]').parent().find("button, a").prop('disabled', true);
return this._super();
},
rte_changed: function () {
this.$('button[data-action=save]').parent().find("button, a").prop('disabled', false);
return this._super();
},
});
});
@@ -1,295 +0,0 @@
odoo.define('website_version.menu', function (require) {
'use strict';
var ajax = require('web.ajax');
var core = require('web.core');
var Widget = require('web.Widget');
var base = require('web_editor.base');
var _t = core._t;
var qweb = core.qweb;
var _get_context = base.get_context;
base.get_context = function (dict) {
return _.extend({ 'version_id': $("#version-menu-button").data("version_id")|0 }, _get_context(dict));
};
ajax.loadXML('/website_version/static/src/xml/version_templates.xml', qweb);
var EditorVersion = Widget.extend({
start: function() {
var self = this;
self.$el.on('click', 'a[data-action]', function(ev) {
ev.preventDefault();
self[$(this).data('action')](ev);
});
this.$el.find('#version-menu-button').click(function() {
var view_id = parseInt($('html').attr('data-view-xmlid'));
ajax.jsonRpc( '/website_version/all_versions', 'call', {'view_id': view_id}).then(function (result) {
self.$el.find(".o_version_choice").remove();
self.$el.find(".first_divider").before(qweb.render("website_version.all_versions", {versions:result}));
});
ajax.jsonRpc( '/website_version/has_experiments', 'call', {'view_id': view_id}).then(function (result) {
self.$el.find(".o_experiment").remove();
if(result){
self.$el.find(".create_experiment").after(qweb.render("website_version.experiment_menu"));
}
});
});
return this._super();
},
duplicate_version: function(event) {
var version_id = base.get_context().version_id;
var wizardA = $(qweb.render("website_version.new_version",{'default_name': moment().format('L')}));
wizardA.appendTo($('body')).modal({"keyboard" :true});
wizardA.on('click','.o_create', function(){
wizardA.find('.o_message').remove();
var version_name = wizardA.find('.o_version_name').val();
if(version_name.length == 0){
wizardA.find(".o_version_name").after("<p class='o_message' style='color : red'> *"+_t("This field is required")+"</p>");
}
else{
wizardA.modal("hide");
ajax.jsonRpc( '/website_version/create_version', 'call', { 'name': version_name, 'version_id': version_id}).then(function (result) {
var wizard = $(qweb.render("website_version.dialogue",{message:_.str.sprintf("You are now working on version: %s.", version_name),
dialogue:_.str.sprintf("If you edit this page or others, all changes will be recorded in the version. It will not be visible by visitors until you publish the version.")}));
wizard.appendTo($('body')).modal({"keyboard" :true});
wizard.on('click','.o_confirm', function(){
window.location.href = '\?enable_editor';
});
wizard.on('hidden.bs.modal', function () {$(this).remove();});
}).fail(function(){
var wizard = $(qweb.render("website_version.message",{message:_t("This name already exists.")}));
wizard.addClass("o_error");
wizard.appendTo($('body')).modal({"keyboard" :true});
wizard.on('hidden.bs.modal', function () {$(this).remove();});
});
}
});
wizardA.on('hidden.bs.modal', function () {$(this).remove();});
},
change_version: function(event) {
var version_id = parseInt($(event.target).closest("li").data("version_id"));
if(! version_id){
version_id = 0;//By default master
}
ajax.jsonRpc( '/website_version/change_version', 'call', { 'version_id':version_id }).then(function (result) {
location.reload();
});
},
delete_version: function(event) {
var version_id = parseInt($(event.target).closest("li").data("version_id"));
var name = $(event.currentTarget).parent().children(':last-child').text();
ajax.jsonRpc( '/website_version/check_version', 'call', { 'version_id':version_id }).then(function (result) {
if (result){
var wizard = $(qweb.render("website_version.message",{message:_.str.sprintf("You cannot delete the %s version because it is in a running or paused experiment", name)}));
wizard.appendTo($('body')).modal({"keyboard" :true});
wizard.on('hidden.bs.modal', function () {$(this).remove();});
}
else{
var wizardA = $(qweb.render("website_version.delete_message",{message:_.str.sprintf("Are you sure you want to delete the %s version ?", name)}));
wizardA.appendTo($('body')).modal({"keyboard" :true});
wizardA.on('click','.o_confirm', function(){
ajax.jsonRpc( '/website_version/delete_version', 'call', { 'version_id':version_id }).then(function (result) {
var wizardB = $(qweb.render("website_version.message",{message:_.str.sprintf("The %s version has been deleted.", result)}));
wizardB.appendTo($('body')).modal({"keyboard" :true});
wizardB.on('click','.o_confirm', function(){
location.reload();
wizardB.on('hidden.bs.modal', function () {$(this).remove();});
});
});
});
wizardA.on('hidden.bs.modal', function () {$(this).remove();});
}
});
},
publish_version: function(event) {
var version_id = base.get_context().version_id;
var name = $('#version-menu-button').attr('data-version_name');
ajax.jsonRpc( '/website_version/diff_version', 'call', { 'version_id':version_id}).then(function (result) {
var wizardA = $(qweb.render("website_version.publish_message",{message:_.str.sprintf("Publish Version %s", name), list:result}));
wizardA.appendTo($('body')).modal({"keyboard" :true});
wizardA.on('click','.o_confirm', function(){
wizardA.find('.o_message').remove();
var check = wizardA.find('.o_check').is(':checked');
var copy_master_name = wizardA.find('.o_name').val();
if(check){
if(copy_master_name.length == 0){
wizardA.find(".o_name").after("<p class='o_message' style='color : red'> *"+_t("This field is required")+"</p>");
}
else{
ajax.jsonRpc( '/website_version/publish_version', 'call', { 'version_id':version_id, 'save_master':true, 'copy_master_name':copy_master_name}).then(function (result) {
var wizardB = $(qweb.render("website_version.dialogue",{message:_.str.sprintf("The %s version has been published", result), dialogue:_.str.sprintf("The master has been saved on a new version called %s.",copy_master_name)}));
wizardB.appendTo($('body')).modal({"keyboard" :true});
wizardB.on('click','.o_confirm', function(){
location.reload();
});
wizardB.on('hidden.bs.modal', function () {$(this).remove();});
});
}
}
else{
ajax.jsonRpc( '/website_version/publish_version', 'call', { 'version_id':version_id, 'save_master':false, 'copy_master_name':""}).then(function (result) {
var wizardC = $(qweb.render("website_version.message",{message:_.str.sprintf("The %s version has been published.", result)}));
wizardC.appendTo($('body')).modal({"keyboard" :true});
wizardC.on('click','.o_confirm', function(){
location.reload();
});
wizardC.on('hidden.bs.modal', function () {$(this).remove();});
});
}
});
wizardA.on('click','input[name="optionsRadios"]', function(){
wizardA.find('.o_message').remove();
wizardA.find('.o_name').toggle( wizardA.find('.o_check').is(':checked') );
});
wizardA.on('hidden.bs.modal', function () {$(this).remove();});
});
},
diff_version: function(event) {
var version_id = base.get_context().version_id;
var name = $('#version-menu-button').data('version_name');
ajax.jsonRpc( '/website_version/diff_version', 'call', { 'version_id':version_id}).then(function (result) {
var wizard = $(qweb.render("website_version.diff",{list:result, version_name:name}));
wizard.appendTo($('body')).modal({"keyboard" :true});
wizard.on('click','.o_confirm', function(){});
wizard.on('hidden.bs.modal', function () {$(this).remove();});
});
},
google_analytics: function(event){
window.location.href = 'https://www.google.com/analytics/web';
},
create_experiment: function() {
var self = this;
var view_id = parseInt($('html').attr('data-view-xmlid'));
ajax.jsonRpc( '/website_version/all_versions_all_goals', 'call', { 'view_id': view_id }).then(function (result) {
var wizardA = $(qweb.render("website_version.create_experiment",{versions:result.tab_version, goals:result.tab_goal, config:result.check_conf}));
wizardA.appendTo($('body')).modal({"keyboard" :true});
wizardA.on('click','.o_launch', function(){
wizardA.find('.o_message').remove();
var name = wizardA.find('.o_name').val();
var tab = wizardA.find('.o_version');
var result = [];
var i;
for (var i = 0; i < tab.length; i++){
if ($(tab[i]).is(':checked')) {
result.push(parseInt($(tab[i]).attr('data-version_id')));
}
}
var goal_id = wizardA.find('.box').val();
var check = true;
if (name.length == 0){
wizardA.find(".o_name").after("<p class='o_message' style='color : red'> *"+_t("This field is required")+"</p>");
check = false;
}
if (result.length == 0 && check){
wizardA.find(".o_versions").after("<p class='o_message' style='color : red'> *"+_t("You must select at least one version which is not Master.")+"</p>");
check = false;
}
if(check){
ajax.jsonRpc( '/website_version/launch_experiment', 'call', { 'name':name, 'version_ids':result, 'goal_id':goal_id }).then(function (existing_experiment) {
if (!existing_experiment['existing']){
var wizardB = $(qweb.render("website_version.dialogue",{message:_.str.sprintf("Your %s experiment is created.", name), dialogue:_t(" Now you can manage this experiment by clicking on Manage A/B tests.")}));
wizardB.appendTo($('body')).modal({"keyboard" :true});
wizardB.on('click','.o_confirm', function(){
location.reload();
});
wizardB.on('hidden.bs.modal', function () {$(this).remove();});
}
else{
if(existing_experiment['existing'] == 1){
wizardA.find(".o_versions").after("<p class='o_message' style='color : red'> *"+_.str.sprintf("Your %s experiment cannot be launched because this experiment contains a view which is already used in the running %s experiment.", name, existing_experiment['name'])+"</p>");
}
else{
wizardA.find(".o_versions").after("<p class='o_message' style='color : red'> *"+_.str.sprintf("You cannot have more then 24 running/paused experiments.")+"</p>");
}
}
});
}
});
wizardA.on('click','.o_configure', function(){
var website_id = $('html').attr('data-website-id');
window.location.href ='/web#id='+website_id+'&view_type=form&model=website&action=website_version.action_website_view';
});
wizardA.on('click','.o_validate_0', function(){
wizardA.find('.o_message').remove();
var website_id = $('html').attr('data-website-id');
var ga_key = wizardA.find('.o_ga_key').val();
var view_id = wizardA.find('.o_view_id').val();
var client_id = wizardA.find('.o_client_id').val();
var client_secret = wizardA.find('.o_client_secret').val();
if(ga_key.length == 0 || view_id.length == 0 || client_id.length == 0 || client_secret.length == 0){
wizardA.find(".o_configure_ab").after("<p class='o_message' style='color : red'> *"+_t("You must fill all the fields.")+"</p>");
}
else{
ajax.jsonRpc( '/website_version/set_google_access', 'call', {'ga_key':ga_key, 'view_id':view_id, 'client_id':client_id, 'client_secret':client_secret}).then(function (result) {
var context = base.get_context();
ajax.jsonRpc( '/website_version/google_access', 'call', {
fromurl: window.location.href,
local_context: context
}).done(function(o) {
if (o.status === "need_auth") {
var wizardC = $(qweb.render("website_version.message",{message:_t("You will be redirected to Google to authorize access to your Analytics Account!")}));
wizardC.appendTo($('body')).modal({"keyboard" :true});
wizardC.on('click','.o_confirm', function(){
window.location.href = o.url;
});
wizardC.on('hidden.bs.modal', function () {$(this).remove();});
}
else if (o.status === "need_config_from_admin"){
if (confirm(_t("The Google Management API key needs to be configured before you can use it, do you want to do it now?"))) {
window.location.href = o.action;
}
}
}).always(function() { $('button.GoogleAccess').prop('disabled', false); });
});
}
});
wizardA.on('click','.o_validate_2', function(){
var website_id = $('html').attr('data-website-id');
var ga_key = wizardA.find('.o_ga_key').val();
var view_id = wizardA.find('.o_view_id').val();
if(ga_key.length == 0 || view_id.length == 0){
wizardA.find(".o_configure_ab").after("<p class='o_message' style='color : red'> *"+_t("You must fill all the fields.")+"</p>");
}
else{
ajax.jsonRpc( '/website_version/set_google_access', 'call', {'ga_key':ga_key, 'view_id':view_id, 'client_id':0, 'client_secret':0});
}
});
wizardA.on('hidden.bs.modal', function () {$(this).remove();});
});
},
manage_experiment: function() {
window.location.href = '/web#return_label=Website&action=website_version.action_experiment';
},
statistics: function() {
window.open('https://www.google.com/analytics/web/?authuser=0#report/siteopt-experiments/','_blank');
}
});
$(document).ready(function() {
var version = new EditorVersion();
version.setElement($("#version-menu"));
version.start();
});
return EditorVersion;
});
@@ -1,192 +0,0 @@
odoo.define('website_version.tour', function (require) {
'use strict';
var core = require('web.core');
var Tour = require('web.Tour');
var _t = core._t;
Tour.register({
id: 'versioning',
name: "Tutorial versioning",
path: '/',
mode: 'tutorial',
steps: [
//1.
{
title: _t("Welcome to the tutorial"),
content: _t("This tutorial will guide you to build a version of your home page."),
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
},
{
title: _t("Click on Version"),
content: _t("You can create a version for every page of your website."),
popover: { fixed: true },
element: 'a#version-menu-button',
},
{
title: _t("Click on New version"),
popover: { fixed: true },
placement: 'left',
element: 'a[data-action="duplicate_version"]:first',
},
{
title: _t("Give a version name"),
content: _t("Give a clever name to retrieve it easily."),
popover: { fixed: true },
waitFor: '.modal button.btn-primary.o_create',
element: '.modal input.o_version_name[type="text"]',
sampleText: 'Test',
},
{
title: _t("Validate the version name"),
placement: 'right',
popover: { fixed: true },
element: '.modal button.btn-primary.o_create',
},
{
title: _t("Confirm"),
placement: 'right',
popover: { fixed: true },
waitNot: '.modal input.form-control[type=text]',
element: '.modal button.o_confirm',
},
{
title: _t("You are on your new version"),
content: _t("All the modifications you will do, will be saved in this version."),
waitNot: '.modal button.o_confirm',
},
{
snippet: '#snippet_structure .oe_snippet:first',
placement: 'bottom',
title: _t("Drag & Drop a Banner"),
content: _t("Drag the Banner block and drop it in your page."),
popover: { fixed: true },
},
{
waitFor: '.oe_overlay_options .oe_options:visible',
element: '#wrapwrap .carousel:first div.carousel-content',
placement: 'top',
title: _t("Customize banner's text"),
content: _t("Click in the text and start editing it."),
sampleText: 'Here, a customized text',
},
{
waitNot: '#wrap .carousel:first div.carousel-content:has(h2:'+
'containsExact('+_t('Your Banner Title')+')):has(h3:'+
'containsExact('+_t('Click to customize this text')+'))',
element: '.oe_snippet_parent:visible',
placement: 'bottom',
title: _t("Get banner properties"),
content: _t("Select the parent container to get the global options of the banner."),
popover: { fixed: true },
},
{
element: '.oe_overlay_options .oe_options:visible',
placement: 'left',
title: _t("Customize the banner"),
content: _t("Customize any block through this menu. Try to change the background of the banner."),
popover: { next: _t("Continue") },
},
{
snippet: '#snippet_structure .oe_snippet:eq(7)',
placement: 'bottom',
title: _t("Drag & Drop This Block"),
content: _t("Drag the <em>'Features'</em> block and drop it below the banner."),
popover: { fixed: true },
},
{
waitFor: '.oe_overlay_options .oe_options:visible',
element: 'button[data-action=save]',
placement: 'right',
title: _t("Save your modifications"),
content: _t("Publish your page by clicking on the <em>'Save'</em> button."),
popover: { fixed: true },
},
{
waitNot: 'button[data-action=save]:visible',
title: _t("Good Job!"),
content: _t("Well done, you created a version of your homepage."),
popover: { next: _t("Continue") },
},
//2.
{
title: _t("Publish the version"),
content: _t("Now we will publish your version in production."),
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
},
{
title: _t("Click on Version"),
element: 'a#version-menu-button',
popover: { fixed: true },
},
{
title: _t("Click on Publish Version"),
placement: 'left',
element: 'a[data-action="publish_version"]:first',
popover: { fixed: true },
},
{
title: _t("Click on Publish button"),
element: '.modal button.o_confirm',
placement: 'right',
},
{
title: _t("Confirm"),
placement: 'right',
element: '.modal button.o_confirm[data-dismiss]',
popover: { fixed: true },
},
//3.
{
title: _t("Delete the version"),
content: _t("Now we will delete the version you have just published."),
waitNot: '.modal button.o_confirm[data-dismiss]',
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
},
{
title: _t("Click on Version"),
element: 'a#version-menu-button',
popover: { fixed: true },
},
{
title: _t("Delete Version Test"),
element: 'li > a[data-action="delete_version"]:last',
popover: { fixed: true },
},
{
title: _t("Click on delete version button"),
placement: 'right',
element: '.modal:has(.cancel) button.o_confirm',
popover: { fixed: true },
},
{
title: _t("Confirm"),
placement: 'right',
element: '.modal:not(:has(.cancel)) button.o_confirm[data-dismiss]',
popover: { fixed: true },
},
{
title: _t("Finish"),
content: _t("Felicitation, now you are able to edit and manage your versions."),
waitNot: '.modal button.o_confirm[data-dismiss]',
},
]
});
});
@@ -1,43 +0,0 @@
odoo.define('website_version.widget', function (require) {
"use strict";
var core = require('web.core');
var form_common = require('web.form_common');
var framework = require('web.framework');
var pyeval = require('web.pyeval');
var _t = core._t;
var rtoken = form_common.AbstractField.extend({
template: 'website_version.GoogleAccess',
start: function() {
var self = this;
this.$el.on('click', 'button.GoogleAccess', function() {
self.allow_google();
});
},
allow_google: function() {
var self = this;
$('button.GoogleAccess').prop('disabled', true);
var context = pyeval.eval('context');
self.rpc('/website_version/google_access', {
fromurl: window.location.href,
local_context: context
}).done(function(o) {
if (o.status === "need_auth") {
alert(_t("You will be redirected to Google to authorize access to your Analytics Account!"));
framework.redirect(o.url);
}
else if (o.status === "need_config_from_admin"){
if (confirm(_t("The Google Management API key needs to be configured before you can use it, do you want to do it now?"))) {
self.do_action(o.action);
}
}
}).always(function() { $('button.GoogleAccess').prop('disabled', false); });
}
});
core.form_widget_registry.add('rtoken', rtoken);
});
@@ -1,467 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="website_version.all_versions">
<t t-foreach="versions" t-as="item">
<li class="o_version_choice" t-att-data-version_id="item.id">
<a href="#" data-action="delete_version" style="position: absolute; right: 0px;" class="pull-right"><i class="fa fa-trash-o fa-fw"></i></a>
<a href="#" data-action="change_version">
<t t-if="item.bold == 0 "><t t-esc="item.name"></t></t>
<t t-if="item.bold == 1 "><b><t t-esc="item.name"></t></b></t>
</a>
</li>
</t>
</t>
<t t-extend="web_editor.editorbar">
<t t-jquery=".navbar form button" t-operation="replace">
<div class="btn-group">
<button type="button" data-action="save" class="btn btn-primary btn-xs">Save</button>
<button type="button" class="btn btn-primary btn-xs dropdown-toggle option_choice" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li class="o_first_choice"><a href="#" id="save_as_new_version" data-action="save_as_new_version"
class="btn btn-link btn-xs o_version">Save as New Version</a>
</li>
</ul>
</div>
</t>
</t>
<t t-name="website_version.all_options">
<li class="o_second_choice">
<a href="#" id="save_and_publish" data-action="save_and_publish"
class="btn btn-link btn-xs o_version"><t t-esc="version"></t></a>
</li>
</t>
<t t-name="website_version.experiment_menu">
<li class="o_experiment"><a href="#" data-action="manage_experiment">Manage A/B tests</a></li>
<li class="o_experiment"><a href="#" data-action="statistics">Statistics</a></li>
</t>
<t t-name="website_version.GoogleAccess">
<div id="CheckGoogleAccess" class="odoo_google_token" >
<button class="GoogleAccess"> Authorize google </button>
</div>
</t>
<t t-name="website_version.create_experiment">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
<h4 class="modal-title">Launch A/B Tests</h4>
</div>
<div class="modal-body">
<t t-if="versions.length != 0 and config == 1">
<form id="productForm" class="form-horizontal" role="form">
<div class="form-group form-group">
<label class="col-sm-3 control-label">Experiment Name</label>
<div class="col-sm-8">
<input type="text" class="form-control form-field-label o_name o_required_field"/>
</div>
</div>
<div class="form-group form-group">
<label class="col-sm-3 control-label">Objective: </label>
<div class="col-sm-8 ">
<select class="form-control col-sm-2 box">
<t t-foreach="goals" t-as="item">
<option t-att-value="item.id"><t t-esc="item.name"></t></option>
</t>
</select>
</div>
</div>
<div class="form-group form-group">
<div class="col-sm-3"></div>
<div class="checkbox col-sm-8">
<label>
<input type="checkbox" checked="checked" disabled="disabled"/> Master
</label>
</div>
</div>
<div class="o_versions">
<t t-foreach="versions" t-as="item">
<div class="form-group form-group-lg">
<div class="col-sm-3"></div>
<div class="checkbox col-sm-8">
<label>
<input type="checkbox" class="o_version" t-att-data-version_id="item.id"/> <t t-esc="item.name"></t>
</label>
</div>
</div>
</t>
</div>
</form>
</t>
<t t-if="versions.length == 0 and config == 1">
<div>
<p>You must have at least one version for this page to create a new experiment.</p>
</div>
</t>
<t t-if= "config == 0">
<div class="o_configure_ab">
<p>Odoo uses Google Analytics to track the performances of an A/B testing experiment comparing several versions.</p>
</div>
<form id="productForm" class="form-horizontal" role="form">
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
To get your GA Key and your View ID
<span class="fa fa-info-circle" />
</a>
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne" style="overflow: hidden">
<div class="panel-body">
<ul>
<li> Go to <a href='https://www.google.com/analytics/' target='_blank'>https://www.google.com/analytics/</a>
and connect you.
<br/><br/><img src=
'/website_version/static/src/img/GA/GA_login.png'
class='analytics_img_tuto'/>
</li>
<li>
Click on <b>"Admin"</b>.
<br/><br/><img src='/website_version/static/src/img/GA/GA_admin.png' class='analytics_img_tuto'/>
</li>
<li>
Click on <b>"Tracking Code"</b>.
<br/><br/><img src='/website_version/static/src/img/GA/GA_tracking_code.png' class='analytics_img_tuto'/>
</li>
<li>
Copy the <b>"Tracking ID"</b> and paste it in the field Google Analytics key.
<br/><br/><img src='/website_version/static/src/img/GA/GA_tracking_id.png' class='analytics_img_tuto'/>
</li>
<li>
Click on <b>"Admin"</b> and click on <b>"View Settings"</b>.
<br/><br/><img src='/website_version/static/src/img/GA/GA_view_settings.png' class='analytics_img_tuto'/>
</li>
<li>
Copy the <b>"View ID"</b> and paste it in the field View ID.
<br/><br/><img src='/website_version/static/src/img/GA/GA_view_id.png' class='analytics_img_tuto'/>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="form-group form-group">
<label class="col-sm-3 control-label">GA Key</label>
<div class="col-sm-8">
<input type="text" class="form-control form-field-label o_ga_key o_required_field"/>
</div>
</div>
<div class="form-group form-group">
<label class="col-sm-3 control-label">View ID</label>
<div class="col-sm-8">
<input type="text" class="form-control form-field-label o_view_id o_required_field"/>
</div>
</div>
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
To get your Client ID and your Client Secret, follow these steps
<span class="fa fa-info-circle" />
</a>
</h4>
</div>
<div id="collapseTwo" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne" style="overflow: hidden">
<div class="panel-body">
<ul>
<li> Connect on your google account and go to <a href='https://console.developers.google.com' target='_blank'>https://console.developers.google.com</a> </li>
<li>
Click on <b>"Create Project"</b> and enter a project name.
<br/><br/><img src='/website_version/static/src/img/GC/GC_create_project.png'
class='analytics_img_tuto'/>
<br/><br/><img src='/website_version/static/src/img/GC/GC_new_project.png'
class='analytics_img_tuto'/>
</li>
<li> In the menu on left side, select the sub menu APIs (from menu APIs and auth) and activate <b>"Analytics API"</b> by clicking on button "OFF".
<br/> When it's done, check that the button of <b>"Calendar API"</b> is well in green and with text "ON"
<br/><br/><img src='/website_version/static/src/img/GC/GC_API.png'
class='analytics_img_tuto'/>
<br/><br/><img src='/website_version/static/src/img/GC/GC_off_api.png'
class='analytics_img_tuto'/>
<br/><br/><img src='/website_version/static/src/img/GC/GC_on_api.png'
class='analytics_img_tuto'/>
</li>
<li>
In the menu on left side, select the sub menu <b>'Credentials'</b> (from menu APIs and auth) and click on button <b>'Create New Client ID'</b>
<br/><br/><img src='/website_version/static/src/img/GC/GC_credentials.png'
class='analytics_img_tuto'/>
<br/><br/><img src='/website_version/static/src/img/GC/GC_create_new_client_id.png'
class='analytics_img_tuto'/>
</li>
<li> Fill in the Name of application and check that the platform is well on <b>'Web Application'</b>.<br/>
<br/> You should now configure the allowed pages on which you will be redirected. To do it, you need to complete the field <b>"Redirect RI"</b>
and set as value (your own domain followed by <i>"/google_account/authentication"</i>) :
<br/> You can now click on <b>'Create Client ID'</b>
<br/><br/><img src='/website_version/static/src/img/GC/GC_client_id.png'
class='analytics_img_tuto'/>
</li>
<li>Once done, you will have the both informations (<b>Client ID</b> and <b>Client Secret</b>) that you need to insert in the 2 fields below !
<br/><br/><img src='/website_version/static/src/img/GC/GC_copy.png'
class='analytics_img_tuto'/>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="form-group form-group">
<label class="col-sm-3 control-label">Client ID</label>
<div class="col-sm-8">
<input type="text" class="form-control form-field-label o_client_id o_required_field"/>
</div>
</div>
<div class="form-group form-group">
<label class="col-sm-3 control-label">Client Secret</label>
<div class="col-sm-8">
<input type="text" class="form-control form-field-label o_client_secret o_required_field"/>
</div>
</div>
</form>
</t>
<t t-if= "config == 2">
<div class="o_configure_ab">
<p>Odoo uses Google Analytics to track the performances of an A/B testing experiment comparing several versions.</p>
</div>
<form id="productForm" class="form-horizontal" role="form">
<div class="form-group form-group">
<label class="col-sm-3 control-label">GA Key</label>
<div class="col-sm-8">
<input type="text" class="form-control form-field-label o_ga_key o_required_field"/>
</div>
</div>
<div class="form-group form-group">
<label class="col-sm-3 control-label">View ID</label>
<div class="col-sm-8">
<input type="text" class="form-control form-field-label o_view_id o_required_field"/>
</div>
</div>
</form>
</t>
</div>
<div class="modal-footer">
<t t-if="versions.length != 0 and config == 1">
<div class="btn-group">
<button type="button" class="btn btn-primary o_launch">Launch</button>
</div>
</t>
<t t-if= "config == 0 or config == 2">
<div class="btn-group">
<t t-if= "config == 0">
<button type="button" class="btn btn-primary o_validate_0">Validate</button>
</t>
<t t-if= "config == 2">
<button type="button" class="btn btn-primary o_validate_2" data-dismiss="modal">Validate</button>
</t>
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="#" class="btn btn-link btn-xs o_configure">Configure</a></li>
</ul>
</div>
</t>
or
<a href="#" class="btn btn-link btn-xs" data-dismiss="modal">Cancel</a>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</t>
<t t-name="website_version.message">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
<h4 class="modal-title"><t t-esc="message"></t></h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary o_confirm" data-dismiss="modal">Ok</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</t>
<t t-name="website_version.dialogue">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
<h4 class="modal-title"><t t-esc="message"></t></h4>
</div>
<div class="modal-body">
<p><t t-esc="dialogue"></t></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary o_confirm" data-dismiss="modal">Ok</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</t>
<t t-name="website_version.diff">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
<h4 class="modal-title">Version: <t t-esc="version_name"></t></h4>
</div>
<div class="modal-body">
<t t-if="list.length != 0">
<ul>
<t t-foreach="list" t-as="item">
<li><a t-att-href="item.url"> <b><t t-esc="item.name"></t></b> </a></li>
</t>
</ul>
<p>List of pages that have been modified in version <t t-esc="version_name"></t>
compared to master. If you publish this version, all pages will be updated at once.
</p>
</t>
<t t-if="list.length == 0">
<p>There is no difference with Master</p>
</t>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary o_confirm" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</t>
<t t-name="website_version.delete_message">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
<h4 class="modal-title"><t t-esc="message"></t></h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary o_confirm" data-dismiss="modal">Delete Version</button>
or
<a href="#" class="btn btn-link btn-xs cancel" data-dismiss="modal">Cancel</a>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</t>
<t t-name="website_version.publish">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
<h4 class="modal-title"><t t-esc="message"></t></h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary o_confirm" data-dismiss="modal">Publish</button>
or
<a href="#" class="btn btn-link btn-xs cancel" data-dismiss="modal">Cancel</a>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</t>
<t t-name="website_version.publish_message">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
<h4 class="modal-title"><t t-esc="message"></t></h4>
</div>
<div class="modal-body">
<p>By publishing this version, you will overwrite the following master pages:</p>
<t t-if="list.length != 0">
<ul>
<t t-foreach="list" t-as="item">
<li><t t-esc="item.name"></t> </li>
</t>
</ul>
</t>
<t t-if="list.length == 0">
<p>There is no difference with Master</p>
</t>
<form id="productForm" class="form-horizontal" role="form">
<div class="radio">
<label>
<input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked="checked"/>
Publish version
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="optionsRadios" id="optionsRadios2" value="option2" class="o_check"/>
Publish and copy the current version
<input type="text" class="form-control o_name o_required_field" style="display: none;"/>
</label>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary o_confirm">Publish</button>
<a href="#" class="btn btn-link btn-xs" data-dismiss="modal">Cancel</a>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</t>
<t t-name="website_version.new_version">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
<h4 class="modal-title">New Version</h4>
</div>
<div class="modal-body">
<p class="text-muted">
A version allows to modify several pages, without publishing the changes directly.
You can also launch A/B tests to analyse the performance of different versions.
</p>
<form id="productForm" class="form-horizontal" role="form">
<div class="form-group form-group">
<label class="col-sm-3 control-label">New Version</label>
<div class="col-sm-8">
<input type="text" class="form-control form-field-label o_version_name o_required_field" t-attf-value="{{default_name}}"/>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary o_create">Create</button>
<a href="#" class="btn btn-link btn-xs" data-dismiss="modal">Cancel</a>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</t>
</templates>
-1
View File
@@ -1 +0,0 @@
from . import test_website_version_all, test_ui
-8
View File
@@ -1,8 +0,0 @@
import openerp.tests
@openerp.tests.common.at_install(False)
@openerp.tests.common.post_install(True)
class TestUi(openerp.tests.HttpCase):
def test_01_versioning(self):
self.phantom_js("/", "odoo.__DEBUG__.services['web.Tour'].run('versioning', 'test')", "odoo.__DEBUG__.services['web.Tour'].tours.versioning", login='admin')
@@ -1,15 +0,0 @@
from . import test_website_version_base
class TestWebsiteVersionAll(test_website_version_base.TestWebsiteVersionBase):
def test_copy_version(self):
""" Testing version_copy"""
view_0_0_0_0_id, version_id, website_id = self.view_0_0_0_0.id, self.version.id, self.website.id
copy_version = self.website_version_version.create({'name': 'copy_version_0_0_0_0', 'website_id': website_id})
self.version.copy_version(copy_version.id)
view_copy_version = copy_version.view_ids[0]
self.env.context = {'version_id': version_id}
view_0_0_0_0 = self.ir_ui_view.browse(view_0_0_0_0_id)
self.assertEqual(view_copy_version.arch, view_0_0_0_0.arch, 'website_version: copy_version: website_version must have in snpashot_copy the same views then in version_0_0_0_0')
@@ -1,22 +0,0 @@
from openerp.tests import common
class TestWebsiteVersionBase(common.TransactionCase):
def setUp(self):
super(TestWebsiteVersionBase, self).setUp()
cr, uid = self.cr, self.uid
# Usefull models
self.ir_ui_view = self.env['ir.ui.view']
self.website_version_version = self.env['website_version.version']
self.website = self.env['website']
self.ir_model_data = self.env['ir.model.data']
#Usefull objects
master_view = self.registry('ir.model.data').xmlid_to_object(cr, uid, 'website.website2_homepage', context=None)
self.arch_master = master_view.arch
self.version = self.registry('ir.model.data').xmlid_to_object(cr, uid, 'website_version.version_0_0_0_0', context=None)
self.website = self.registry('ir.model.data').xmlid_to_object(cr, uid, 'website.website2', context=None)
self.view_0_0_0_0 = self.registry('ir.model.data').xmlid_to_object(cr, uid, 'website_version.website2_homepage_other', context=None)
self.arch_0_0_0_0 = self.view_0_0_0_0.arch
@@ -1,239 +0,0 @@
<?xml version="1.0"?>
<openerp>
<data>
<record id="action_experiment" model="ir.actions.act_window">
<field name="name">Experiments</field>
<field name="res_model">website_version.experiment</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{}</field>
</record>
<record model="ir.ui.view" id="view_experiment_kanban">
<field name="name">Experiment Kanban</field>
<field name="model">website_version.experiment</field>
<field name="arch" type="xml">
<kanban default_group_by="state" string="Experiments" class="oe_background_grey">
<field name="sequence" widget="handle" />
<field name="name"/>
<field name="website_id"/>
<field name="experiment_version_ids"/>
<field name="color"/>
<field name="message_follower_ids"/>
<templates>
<field name="state"/>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_global_click_edit oe_semantic_html_override oe_kanban_card">
<div class="o_dropdown_kanban dropdown">
<a class="dropdown-toggle btn" data-toggle="dropdown" href="#" >
<span class="fa fa-bars fa-lg"/>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<li><a type="delete">Delete</a></li>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>
</div>
<!-- kanban note -->
<div class="oe_kanban_content">
<!-- title -->
<field name="name"/> on <field name="website_id"/>
</div>
<div class="oe_clear"></div>
<div> <field name="version_number"/> versions </div>
<div> Creation :<field name="create_date" /> </div>
<div class="oe_right">
<t t-foreach="record.message_follower_ids.raw_value" t-as="follower">
<img t-att-src="kanban_image('res.partner', 'image_small', follower)" width="24" height="24" class="oe_kanban_avatar" t-att-data-member_id="follower"/>
</t>
</div>
<div class="oe_clear"></div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="action_analytic" model="ir.actions.act_url">
<field name="name">Google analytics</field>
<field name="url">https://www.google.com/analytics/web/?authuser=0#report/siteopt-experiments/</field>
<field name="target">self</field>
</record>
<record model="ir.ui.view" id="experiment_form_view">
<field name="name">experiment.form</field>
<field name="model">website_version.experiment</field>
<field name="arch" type="xml">
<form string="Experiment Form">
<header>
<field name="state" widget="statusbar" statusbar_visible="running,paused,ended" clickable="True"/>
</header>
<sheet string="Exp">
<button icon="fa-line-chart" name="website_version.action_analytic" String="Statistics" action="action"
type="action" class="pull-right" />
<div class="oe_title">
<field name="google_id" invisible="1"/>
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" attrs="{'readonly' : [('google_id', '!=', False)] }"/>
</h1>
</div>
<group col="4">
<field name="website_id" attrs="{'readonly' : [('google_id', '!=', False)] }"/>
<field name="google_id" readonly="1" groups="base.group_no_one"/>
<label for="goal_id"/>
<div>
<field name="goal_id" class="oe_inline" widget="selection" attrs="{'readonly' : [('google_id', '!=', False)] }"/>
<button name="update_goals" string="(Sync)" type="object" context="{'website_id': website_id}" class="oe_link oe_edit_only"/>
</div>
</group>
<notebook colspan="4">
<page string="Versions in experiment" colspan="4" >
<field name="experiment_version_ids" colspan="4" context="{'website_id': website_id,
'google_id': google_id}" attrs="{'readonly' : [('google_id', '!=', False)] }">
<tree string="PPP" editable="bottom">
<field name="version_id" string="Versions" domain="[('website_id','=',context.get('website_id'))]" colspan="4"/>
<field name="frequency" colspan="4"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="experiment_tree_view">
<field name="name">experiment.tree</field>
<field name="model">website_version.experiment</field>
<field name="arch" type="xml">
<tree string="Experiment tree">
<field name="name" />
<field name="website_id"/>
<field name="state"/>
<field name="sequence" widget="handle"/>
</tree>
</field>
</record>
<record id="experiment_search" model="ir.ui.view">
<field name="name">experiment.search</field>
<field name="model">website_version.experiment</field>
<field name="arch" type="xml">
<search string="Search Experiment">
<field name="website_id"/>
<field name="state"/>
<group string="Group By">
<filter string="Website" domain="[]" name="my_exps" context="{'group_by':'website_id'}"/>
<filter string="State" domain="[]" context="{'group_by':'state'}"/>
</group>
</search>
</field>
</record>
<!-- <record id="action_experiment_search" model="ir.actions.act_window">
<field name="name">Experiment search</field>
<field name="res_model">website_version.experiment</field>
<field name="view_mode">list</field>
<field name="context">{'search_default_my_exps':1}</field>
</record> -->
<record model="ir.ui.view" id="experiment_version_form_view">
<field name="name">experiment_version.form</field>
<field name="model">website_version.experiment.version</field>
<field name="arch" type="xml">
<form string="Experiment_page Form">
<notebook colspan="4">
<page string="Features" colspan="4" >
<field name="version_id" domain="[('website_id','=',context.get('website_id'))]" colspan="4"/>
<field name="frequency"/>
</page>
</notebook>
</form>
</field>
</record>
<record id="action_version" model="ir.actions.act_window">
<field name="name">Versions</field>
<field name="res_model">website_version.version</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<record model="ir.ui.view" id="version_form_view">
<field name="name">version.form</field>
<field name="model">website_version.version</field>
<field name="arch" type="xml">
<form string="version Form">
<sheet string="Snap">
<group>
<button icon="fa-pencil" name="action_publish" string="Publish" type="object" class="pull-right"/>
</group>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name"/>
</h1>
</div>
<group col="4">
<field name="website_id"/>
</group>
<group colspan="4">
<field name="view_ids" widget="handle" colspan="4"/>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="version_tree_view">
<field name="name">version.tree</field>
<field name="model">website_version.version</field>
<field name="arch" type="xml">
<tree string="version tree">
<field name="name" />
<field name="website_id" />
<field name="create_date" />
</tree>
</field>
</record>
<record id="version_search" model="ir.ui.view">
<field name="name">version.search</field>
<field name="model">website_version.version</field>
<field name="arch" type="xml">
<search string="Search version">
<field name="website_id"/>
<group string="Group By">
<filter string="Website" domain="[]" context="{'group_by':'website_id'}"/>
</group>
</search>
</field>
</record>
<record id="action_website_view" model="ir.actions.act_window">
<field name="name">Website Domain</field>
<field name="res_model">website</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Versionning" id="menu_website_version_root" sequence="30" groups="base.group_website_designer" parent="website.menu_website_configuration" web_icon="website_version,static/description/icon.png"/>
<menuitem action="action_website_view" id="menu_website_view" parent="menu_website_version_root"/>
<menuitem action="action_version" id="menu_action_version" parent="menu_website_version_root" groups="base.group_no_one"/>
<menuitem action="action_experiment" id="menu_action_experiment" parent="menu_website_version_root"/>
<record id="google_analytics_configuration" model="ir.actions.act_window">
<field name="name">Google Analytics Configuration</field>
<field name="res_model">website</field>
<field name="view_mode">form</field>
<field name="target">inline</field>
</record>
</data>
</openerp>
@@ -1,95 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="view_website_config_settings_extend" model="ir.ui.view">
<field name="name">Website settings</field>
<field name="model">website.config.settings</field>
<field name="inherit_id" ref="website.view_website_config_settings"/>
<field name="arch" type="xml">
<field name="website_id" position="replace">
<field name="website_id" invisible="False" on_change="on_change_website_id(website_id)"/>
</field>
</field>
</record>
<record id="view_analytics_config_settings" model="ir.ui.view">
<field name="name">Analytics_settings</field>
<field name="model">base.config.settings</field>
<field name="inherit_id" ref="base_setup.view_general_configuration"/>
<field name="arch" type="xml">
<group name="google_analytics" position="before">
<group>
<label for="id" string="Google Analytics"/>
<div>
<label for="ga_sync"/>
<field name="ga_sync"/>
<div attrs="{'invisible':[('ga_sync','=',False)]}">
<br/><h2>To setup the signin process with Google, first you have to perform the following steps</h2>
<ul>
<li> Connect on your google account and go to <a href='https://console.developers.google.com' target='_blank'>https://console.developers.google.com</a> </li>
<li>
Click on <b>"Create Project"</b> and enter a project name.
<br/><br/><img src='/website_version/static/src/img/GC/GC_create_project.png'
class='analytics_img_tuto'/>
<br/><br/><img src='/website_version/static/src/img/GC/GC_new_project.png'
class='analytics_img_tuto'/>
</li>
<li> In the menu on left side, select the sub menu APIs (from menu APIs and auth) and activate <b>"Analytics API"</b> by clicking on button "OFF".
<br/> When it's done, check that the button of <b>"Calendar API"</b> is well in green and with text "ON"
<br/><br/><img src='/website_version/static/src/img/GC/GC_API.png'
class='analytics_img_tuto'/>
<br/><br/><img src='/website_version/static/src/img/GC/GC_off_api.png'
class='analytics_img_tuto'/>
<br/><br/><img src='/website_version/static/src/img/GC/GC_on_api.png'
class='analytics_img_tuto'/>
</li>
<li>
In the menu on left side, select the sub menu <b>'Credentials'</b> (from menu APIs and auth) and click on button <b>'Create New Client ID'</b>
<br/><br/><img src='/website_version/static/src/img/GC/GC_credentials.png'
class='analytics_img_tuto'/>
<br/><br/><img src='/website_version/static/src/img/GC/GC_create_new_client_id.png'
class='analytics_img_tuto'/>
</li>
<li> Fill in the Name of application and check that the platform is well on <b>'Web Application'</b>.<br/>
<br/> You should now configure the allowed pages on which you will be redirected. To do it, you need to complete the field <b>"Redirect RI"</b>
and set as value (your own domain followed by <i>"/google_account/authentication"</i>) :
<br/> You can now click on <b>'Create Client ID'</b>
<br/><br/><img src='/website_version/static/src/img/GC/GC_client_id.png'
class='analytics_img_tuto'/>
</li>
<li>Once done, you will have the both informations (<b>Client ID</b> and <b>Client Secret</b>) that you need to insert in the 2 fields below !
<br/><br/><img src='/website_version/static/src/img/GC/GC_copy.png'
class='analytics_img_tuto'/>
</li>
<li>Click on <b>Apply</b>
<br/><br/><img src='/website_version/static/src/img/GC/GC_Apply.png'
class='analytics_img_tuto'/>
</li>
<a href="#" class="oe_link">Return at Top</a>
</ul>
</div>
<div>
<label for="ga_client_id" string="Google Client ID" />
<field name="ga_client_id" class="oe_inline"/>
</div>
<div>
<label for="ga_client_secret" string="Google Client Secret"/>
<field name="ga_client_secret" class="oe_inline"/>
</div>
<field name="google_management_authorization" widget="rtoken"/>
</div>
</group>
</group>
</field>
</record>
<record id="action_config_settings_google_management" model="ir.actions.act_window">
<field name="name">API Management Configuration</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">base.config.settings</field>
<field name="view_mode">form</field>
<field name="target">inline</field>
</record>
</data>
</openerp>
@@ -1,72 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Front-end/Back-end integration -->
<template id="user_navbar_version" inherit_id="website.layout" groups="base.group_user">
<xpath expr="//li[@id='customize-menu']" position="before">
<li class="dropdown" id="version-menu" groups="base.group_website_designer">
<a id="version-menu-button" class="dropdown-toggle" data-toggle="dropdown" href="#" t-att-data-version_id="website.get_current_version()[0]" t-att-data-version_name="website.get_current_version()[1]">
Version
<span><t t-esc="website.get_current_version()[1]"></t></span>
<span class="caret"></span>
</a>
<ul class="dropdown-menu version_menu" role="menu">
<t t-if="website.get_current_version()[0] == 0 ">
<li><a href="#" data-action="duplicate_version">New Version</a></li>
</t>
<t t-if="website.get_current_version()[0] != 0 ">
<li><a href="#" data-action="duplicate_version">Duplicate Version</a></li>
<li><a href="#" data-action="publish_version">Publish Version</a></li>
<li><a href="#" data-action="diff_version" groups="base.group_no_one">List Modified Pages</a></li>
</t>
<li class="divider o_publish_version"> </li>
<li class="dropdown-header" style="text-transform: uppercase;">All versions</li>
<t t-if="website.get_current_version()[0] == 0 ">
<li><a href="#" data-action="change_version"><b>Master</b></a></li>
</t>
<t t-if="website.get_current_version()[0] != 0 ">
<li><a href="#" data-action="change_version">Master</a></li>
</t>
<li class="first_divider divider"> </li>
<li class="create_experiment"><a href="#" data-action="create_experiment">Launch A/B tests</a></li>
</ul>
</li>
</xpath>
</template>
<template id="assets_frontend_AB" name="website_AB assets" inherit_id="website.layout">
<xpath expr="//script[@id='tracking_code']" position="replace">
<script id='tracking_code' t-if="website and website.google_analytics_key and not editable">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', _.str.trim('<t t-esc="website.google_analytics_key"/>'), 'auto');
ga_google_analytics_data = <t t-raw="json.dumps(website.google_analytics_data(main_object))"/>;
for(i in ga_google_analytics_data) {
ga('set', i, ga_google_analytics_data[i]);
}
ga('send','pageview');
</script>
</xpath>
</template>
<template id="assets_frontend_menu_version" name="website_menu_version assets" inherit_id="website.assets_editor">
<xpath expr="." position="inside">
<script type="text/javascript" src="/website_version/static/src/js/menu_version.js"></script>
<script type="text/javascript" src="/website_version/static/src/js/edit_version.js"></script>
<script type="text/javascript" src="/website_version/static/src/js/website_version.tour.versioning.js"></script>
<link rel="stylesheet" href="/website_version/static/src/css/menu_version.css"/>
</xpath>
</template>
<template id="assets_backend" name="stock assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/website_version/static/src/css/google_analytics.css"/>
<script type="text/javascript" src="/website_version/static/src/js/widget.js"></script>
</xpath>
</template>
</data>
</openerp>
@@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_website_form_extend">
<field name="name">website.form</field>
<field name="model">website</field>
<field name="inherit_id" ref="website.view_website_form"/>
<field name="priority">1</field>
<field name="arch" type="xml">
<!-- find field name, and insert field name before it -->
<field name="name" position="replace">
</field>
<field name="google_analytics_key" position="before">
<field name="tuto_google_analytics"/>
<div colspan="4">
<div attrs="{'invisible':[('tuto_google_analytics','=',False)]}">
<br/><h2>How to get the Google Analytics Key and the View ID</h2>
<ul>
<li> Go to <a href='https://www.google.com/analytics/' target='_blank'>https://www.google.com/analytics/</a>
and connect you.
<br/><br/><img src='/website_version/static/src/img/GA/GA_login.png' class='analytics_img_tuto'/>
</li>
<li>
Click on <b>"Admin"</b>.
<br/><br/><img src='/website_version/static/src/img/GA/GA_admin.png' class='analytics_img_tuto'/>
</li>
<li>
Click on <b>"Tracking Code"</b>.
<br/><br/><img src='/website_version/static/src/img/GA/GA_tracking_code.png' class='analytics_img_tuto'/>
</li>
<li>
Copy the <b>"Tracking ID"</b> and paste it in the field Google Analytics key.
<br/><br/><img src='/website_version/static/src/img/GA/GA_tracking_id.png' class='analytics_img_tuto'/>
</li>
<li>
Click on <b>"Admin"</b> and click on <b>"View Settings"</b>.
<br/><br/><img src='/website_version/static/src/img/GA/GA_view_settings.png' class='analytics_img_tuto'/>
</li>
<li>
Copy the <b>"View ID"</b> and paste it in the field View ID.
<br/><br/><img src='/website_version/static/src/img/GA/GA_view_id.png' class='analytics_img_tuto'/>
</li>
<li>
Click on Save.
<br/><br/><img src='/website_version/static/src/img/GA/GA_save.png' class='analytics_img_tuto' />
</li>
<li>
Click on Authorize google.
<br/><br/><img src='/website_version/static/src/img/GA/GA_authorize.png' class='analytics_img_tuto' />
</li>
<a href="#" class="oe_link">Return at Top</a>
</ul>
</div>
</div>
</field>
<field name="google_analytics_key" position="after">
<field name="google_analytics_view_id" placeholder="7654321"/>
<field name="google_management_authorization" widget="rtoken"/>
</field>
<field name="company_id" position="after">
<field name="name" class="oe_inline"/>
<field name="company_id"/>
<field name="user_id" context="{'active_test': False}"/>
</field>
<separator name="domain" position="replace">
<separator string="Statistics"/>
</separator>
</field>
</record>
<record id="action_website_view" model="ir.actions.act_window">
<field name="name">Websites</field>
<field name="res_model">website</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<record model="ir.ui.view" id="view_view_form_extend">
<field name="model">ir.ui.view</field>
<field name="inherit_id" ref="base.view_view_form"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="version_id"/>
</field>
<group position="before">
<button icon="fa-pencil" name="action_publish" string="Publish" type="object" class="oe_stat_button pull-right"
attrs="{'invisible': ['|','|',('type', '!=', 'qweb'),('website_id', '=',False), ('version_id', '=', False)]}" />
</group>
</field>
</record>
</data>
</openerp>