[ADD] Versioning Module.
@@ -81,6 +81,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<label for="view_analytics_config_settings" string="Google Analytics"/>
|
||||
<div name="google_analytics">
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<label for="id" string="Google Calendar"/>
|
||||
<div name="google_calendar">
|
||||
|
||||
@@ -14,6 +14,7 @@ OpenERP Website CMS
|
||||
'installable': True,
|
||||
'data': [
|
||||
'data/data.xml',
|
||||
'data/demo.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/ir_ui_view.xml',
|
||||
'views/website_templates.xml',
|
||||
|
||||
@@ -163,7 +163,8 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
def pagenew(self, path, noredirect=False, add_menu=None):
|
||||
xml_id = request.registry['website'].new_page(request.cr, request.uid, path, context=request.context)
|
||||
if add_menu:
|
||||
request.registry['website.menu'].create(request.cr, request.uid, {
|
||||
request.registry['website.menu'].create(
|
||||
request.cr, request.uid, {
|
||||
'name': path,
|
||||
'url': "/page/" + xml_id,
|
||||
'parent_id': request.website.menu_id.id,
|
||||
@@ -202,10 +203,10 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
return request.redirect(redirect)
|
||||
|
||||
@http.route('/website/customize_template_get', type='json', auth='user', website=True)
|
||||
def customize_template_get(self, xml_id, full=False, bundles=False):
|
||||
""" Lists the templates customizing ``xml_id``. By default, only
|
||||
returns optional templates (which can be toggled on and off), if
|
||||
``full=True`` returns all templates customizing ``xml_id``
|
||||
def customize_template_get(self, key, full=False, bundles=False, **kw):
|
||||
""" Get inherit view's informations of the template ``xml_id``. By default, only
|
||||
returns ``customize_show`` templates (which can be active or not), if
|
||||
``full=True`` returns inherit view's informations of the template ``xml_id``.
|
||||
``bundles=True`` returns also the asset bundles
|
||||
"""
|
||||
imd = request.registry['ir.model.data']
|
||||
@@ -215,9 +216,8 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
user = request.registry['res.users']\
|
||||
.browse(request.cr, request.uid, request.uid, request.context)
|
||||
user_groups = set(user.groups_id)
|
||||
|
||||
views = request.registry["ir.ui.view"]\
|
||||
._views_get(request.cr, request.uid, xml_id, bundles=bundles, context=dict(request.context or {}, active_test=False))
|
||||
._views_get(request.cr, request.uid, key, bundles=bundles, context=dict(request.context or {}, active_test=False))
|
||||
done = set()
|
||||
result = []
|
||||
for v in views:
|
||||
@@ -228,7 +228,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
result.append({
|
||||
'name': v.inherit_id.name,
|
||||
'id': v.id,
|
||||
'xml_id': v.xml_id,
|
||||
'key': v.key,
|
||||
'inherit_id': v.inherit_id.id,
|
||||
'header': True,
|
||||
'active': False
|
||||
@@ -237,7 +237,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
||||
result.append({
|
||||
'name': v.name,
|
||||
'id': v.id,
|
||||
'xml_id': v.xml_id,
|
||||
'key': v.key,
|
||||
'inherit_id': v.inherit_id.id,
|
||||
'header': False,
|
||||
'active': v.active,
|
||||
|
||||
@@ -135,7 +135,7 @@ response = request.render("website.template_partner_comment", values)
|
||||
|
||||
<record id="website2" model="website">
|
||||
<field name="name">0.0.0.0</field>
|
||||
<field name="social_twitter">https://twitter.com/Odoo</field>
|
||||
<field name="domain">0.0.0.0</field>
|
||||
<field name="social_facebook">https://www.facebook.com/Odoo</field>
|
||||
<field name="social_googleplus">https://plus.google.com/+Odooapps</field>
|
||||
<field name="social_linkedin">https://www.linkedin.com/company/odoo</field>
|
||||
|
||||
@@ -38,9 +38,13 @@ class ir_http(orm.AbstractModel):
|
||||
)
|
||||
|
||||
def _auth_method_public(self):
|
||||
# TODO: select user_id from matching website
|
||||
if not request.session.uid:
|
||||
request.uid = self.pool['ir.model.data'].xmlid_to_res_id(request.cr, openerp.SUPERUSER_ID, 'base.public_user')
|
||||
domain_name = request.httprequest.environ.get('HTTP_HOST', '').split(':')[0]
|
||||
website_id = self.pool['website']._get_current_website_id(request.cr, openerp.SUPERUSER_ID, domain_name, context=request.context)
|
||||
if website_id:
|
||||
request.uid = self.pool['website'].browse(request.cr, openerp.SUPERUSER_ID, website_id, request.context).user_id.id
|
||||
else:
|
||||
dummy, request.uid = self.pool['ir.model.data'].get_object_reference(request.cr, openerp.SUPERUSER_ID, 'base', 'public_user')
|
||||
else:
|
||||
request.uid = request.session.uid
|
||||
|
||||
|
||||
@@ -23,11 +23,6 @@ class view(osv.osv):
|
||||
'website_id': fields.many2one('website', ondelete='cascade', string="Website"),
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('key_website_id_uniq', 'unique(key, website_id)',
|
||||
'Key must be unique per website.'),
|
||||
]
|
||||
|
||||
_defaults = {
|
||||
'page': False,
|
||||
'customize_show': False,
|
||||
|
||||
@@ -279,16 +279,16 @@ class website(osv.osv):
|
||||
|
||||
@openerp.tools.ormcache(skiparg=4)
|
||||
def _get_current_website_id(self, cr, uid, domain_name, context=None):
|
||||
website_id = 1
|
||||
if request:
|
||||
ids = self.search(cr, uid, [('domain', '=', domain_name)], context=context)
|
||||
if ids:
|
||||
website_id = ids[0]
|
||||
return website_id
|
||||
ids = self.search(cr, uid, [('name', '=', domain_name)], context=context)
|
||||
if ids:
|
||||
return ids[0]
|
||||
else:
|
||||
return self.search(cr, uid, [], context=context)[0]
|
||||
|
||||
def get_current_website(self, cr, uid, context=None):
|
||||
domain_name = request.httprequest.environ.get('HTTP_HOST', '').split(':')[0]
|
||||
website_id = self._get_current_website_id(cr, uid, domain_name, context=context)
|
||||
request.context['website_id'] = website_id
|
||||
return self.browse(cr, uid, website_id, context=context)
|
||||
|
||||
def is_publisher(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
loadTemplates: function () {
|
||||
var self = this;
|
||||
var args = {
|
||||
xml_id: $(document.documentElement).data('view-xmlid'),
|
||||
key: $(document.documentElement).data('view-xmlid'),
|
||||
full: true,
|
||||
bundles: !!$('script[src*=".assets_common"]').length
|
||||
};
|
||||
|
||||
@@ -901,7 +901,7 @@ define(['summernote/summernote'], function () {
|
||||
rte_changed: function () {
|
||||
this.$buttons.save.prop('disabled', false);
|
||||
},
|
||||
save: function () {
|
||||
_save: function () {
|
||||
var self = this;
|
||||
|
||||
var saved = {}; // list of allready saved views and data
|
||||
@@ -969,9 +969,17 @@ define(['summernote/summernote'], function () {
|
||||
});
|
||||
});
|
||||
},
|
||||
save: function () {
|
||||
return this._save().then(function () {
|
||||
website.reload();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Saves an RTE content, which always corresponds to a view section (?).
|
||||
*/
|
||||
save_without_reload: function () {
|
||||
return this._save();
|
||||
},
|
||||
saveElement: function ($el) {
|
||||
var markup = $el.prop('outerHTML');
|
||||
return openerp.jsonRpc('/web/dataset/call', 'call', {
|
||||
@@ -1020,10 +1028,10 @@ define(['summernote/summernote'], function () {
|
||||
if(this.loaded) {
|
||||
return;
|
||||
}
|
||||
openerp.jsonRpc('/website/customize_template_get', 'call', { 'xml_id': this.view_name }).then(
|
||||
openerp.jsonRpc('/website/customize_template_get', 'call', { 'key': this.view_name }).then(
|
||||
function(result) {
|
||||
_.each(result, function (item) {
|
||||
if (item.xml_id === "website.debugger" && !window.location.search.match(/[&?]debug(&|$)/)) return;
|
||||
if (item.key === "website.debugger" && !window.location.search.match(/[&?]debug(&|$)/)) return;
|
||||
if (item.header) {
|
||||
self.$menu.append('<li class="dropdown-header">' + item.name + '</li>');
|
||||
} else {
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
var self = this;
|
||||
|
||||
this.$button = $(openerp.qweb.render('website.snippets_button'))
|
||||
.prependTo(this.parent.$("#website-top-edit ul"))
|
||||
.prependTo(this.parent.$(".js_editor_placeholder"))
|
||||
.find("button");
|
||||
|
||||
this.$button.click(_.bind(this.show_blocks, this));
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
t-att-data-website-id="website.id if editable and website else None"
|
||||
t-att-data-editable="'1' if editable else None"
|
||||
t-att-data-translatable="'1' if translatable else None"
|
||||
t-att-data-view-xmlid="xmlid if editable else None"
|
||||
t-att-data-view-xmlid="xmlid"
|
||||
t-att-data-main-object="repr(main_object) if editable else None"
|
||||
t-att-data-oe-company-name="res_company.name">
|
||||
<head>
|
||||
@@ -88,10 +88,21 @@
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-call-assets="web.assets_common" t-js="false"/>
|
||||
<t t-call-assets="website.assets_frontend" t-js="false"/>
|
||||
<t t-call-assets="web.assets_common"/>
|
||||
<t t-call-assets="website.assets_frontend"/>
|
||||
|
||||
<t t-raw="head or ''" name='layout_head'/>
|
||||
<t t-if="website and website.google_analytics_key">
|
||||
<script id="tracking_code">
|
||||
(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('send','pageview');
|
||||
</script>
|
||||
</t>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapwrap">
|
||||
@@ -133,28 +144,16 @@
|
||||
<t t-raw="0"/>
|
||||
</main>
|
||||
<footer>
|
||||
<div id="footer_container">
|
||||
<div id="footer">
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<t t-call-assets="web.assets_common" t-css="false"/>
|
||||
<t t-call-assets="website.assets_frontend" t-css="false"/>
|
||||
<script t-if="website and website.google_analytics_key">
|
||||
(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('send','pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</template>
|
||||
|
||||
<template id="layout_footer_copyright" inherit_id="website.layout" name="Footer Copyright">
|
||||
<xpath expr="//footer" position="inside">
|
||||
<xpath expr="//div[contains(@id, 'footer')]" position="inside">
|
||||
<div class="container mt16 mb8">
|
||||
<div class="pull-right" t-ignore="true" t-if="not editable">
|
||||
Create a <a href="http://www.odoo.com/page/website-builder">free website</a> with
|
||||
@@ -176,11 +175,8 @@
|
||||
</template>
|
||||
|
||||
<template id="editor_head" inherit_id="website.layout" name="Editor" groups="base.group_website_publisher,base.group_website_designer">
|
||||
<xpath expr='//t[@t-call-assets="website.assets_frontend"][@t-js]' position="after">
|
||||
<t t-call-assets="website.assets_editor" t-js="false"/>
|
||||
</xpath>
|
||||
<xpath expr='//t[@t-call-assets="website.assets_frontend"][@t-css]' position="after">
|
||||
<t t-call-assets="website.assets_editor" t-css="false"/>
|
||||
<xpath expr='//t[@t-call-assets="website.assets_frontend"]' position="after">
|
||||
<t t-call-assets="website.assets_editor"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
@@ -303,7 +299,7 @@
|
||||
</template>
|
||||
|
||||
<template id="footer_custom" inherit_id="website.layout" name="Footer">
|
||||
<xpath expr="//div[@id='footer_container']" position="replace">
|
||||
<xpath expr="//div[@id='footer']" position="replace">
|
||||
<div class="oe_structure" id="footer">
|
||||
<section>
|
||||
<div class="container">
|
||||
@@ -335,7 +331,7 @@
|
||||
|
||||
<template id="footer_default" inherit_id="website.footer_custom" customize_show="True" name="Automatic Footer">
|
||||
<xpath expr="//div[@id='footer']" position="replace">
|
||||
<div class="container hidden-print">
|
||||
<div id="footer" class="container hidden-print">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<h4>Our products & Services</h4>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<data noupdate="1">
|
||||
<record id="default_website" model="website">
|
||||
<field name="name">localhost</field>
|
||||
<field name="domain">localhost</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="language_ids" eval="[(6, 0, [ ref('base.lang_en')])]"/>
|
||||
<field name="default_lang_id" ref="base.lang_en"/>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import models
|
||||
import controllers
|
||||
import tests
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
'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
|
||||
===================
|
||||
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'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/demo.xml',
|
||||
'data/data.xml',
|
||||
],
|
||||
'demo': [],
|
||||
'qweb': ['static/src/xml/*.xml'],
|
||||
'application': True,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import main
|
||||
@@ -0,0 +1,188 @@
|
||||
from openerp import http
|
||||
from openerp.http import request
|
||||
import datetime
|
||||
from openerp.addons.website.controllers.main import Website
|
||||
|
||||
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'] = int(version_id)
|
||||
return version_id
|
||||
|
||||
@http.route(['/website_version/create_version'], type = 'json', auth = "user", website = True)
|
||||
def create_version(self, name, version_id):
|
||||
if name == "":
|
||||
name = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
website_id = request.website.id
|
||||
new_version = request.env['website_version.version'].create({'name':name, 'website_id':website_id})
|
||||
if version_id:
|
||||
request.env['ir.ui.view'].copy_version(version_id, 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_id = int(version_id)
|
||||
x = request.env['website_version.version'].browse(version_id)
|
||||
name = x.name
|
||||
x.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', '=', int(version_id))]))
|
||||
|
||||
@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
|
||||
v = request.env['ir.ui.view'].browse(int(view_id))
|
||||
ver = request.env['website_version.version']
|
||||
website_id = request.website.id
|
||||
result = ver.search_read([('website_id','=',website_id),'|',('view_ids.key','=',v.key),('view_ids.key','=','website.footer_default')],['id','name'])
|
||||
version_id = request.context.get('version_id')
|
||||
check = False
|
||||
for x in result:
|
||||
if x['id'] == version_id:
|
||||
x['bold'] = 1
|
||||
check = True
|
||||
else:
|
||||
x['bold'] = 0
|
||||
#To always show in the menu the current version
|
||||
if not check and version_id:
|
||||
result.append({'id':version_id, 'name':ver.browse(version_id).name, 'bold':1})
|
||||
return result
|
||||
|
||||
@http.route(['/website_version/has_experiments'], type = 'json', auth = "public", website = True)
|
||||
def has_experiments(self, view_id):
|
||||
v = request.env['ir.ui.view'].browse(int(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)]))
|
||||
|
||||
@http.route(['/website_version/publish_version'], type = 'json', auth = "public", website = True)
|
||||
def publish_version(self, version_id, save_master, copy_master_name):
|
||||
request.session['version_id'] = 0
|
||||
return request.env['website_version.version'].publish_version(int(version_id), save_master, copy_master_name)
|
||||
|
||||
@http.route(['/website_version/diff_version'], type = 'json', auth = "public", website = True)
|
||||
def diff_version(self, version_id):
|
||||
mod_version = request.env['website_version.version']
|
||||
version = mod_version.browse(int(version_id))
|
||||
name_list = []
|
||||
for view in version.view_ids:
|
||||
name_list.append(view.name)
|
||||
return name_list
|
||||
|
||||
@http.route(['/website_version/get_analytics'], type = 'json', auth = "public", website = True)
|
||||
def get_analytics(self, view_id):
|
||||
#To get the ExpId and the VarId of the view if it is in a running experiment
|
||||
result = {'ExpId':False, 'VarId': 0}
|
||||
obj_v = request.env['ir.ui.view']
|
||||
view = obj_v.browse(int(view_id))
|
||||
#search all the running experiments with the key of view
|
||||
exp_ids = request.env['website_version.experiment'].search([('experiment_version_ids.version_id.view_ids.key', '=', view.key),('state','=','running'),('experiment_version_ids.version_id.website_id', '=',request.context['website_id'])])
|
||||
if exp_ids:
|
||||
#No overlap between running experiments then we can take the first one
|
||||
x = exp_ids[0]
|
||||
result['ExpId'] = x.google_id
|
||||
if view.version_id:
|
||||
exp_ver_ids = request.env['website_version.experiment_version'].search([('experiment_id','=',exp_ids[0].id),('version_id','=',view.version_id.id)])
|
||||
if exp_ver_ids:
|
||||
y = exp_ver_ids[0]
|
||||
result['VarId'] = y.google_index
|
||||
return result
|
||||
|
||||
@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 = "public", 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, 'google_analytics_view_id':view_id})
|
||||
if client_id and client_secret:
|
||||
icp = request.env['ir.config_parameter']
|
||||
icp.set_param('google_management_client_id', client_id or '', groups=['base.group_system'])
|
||||
icp.set_param('google_management_client_secret', client_secret or '', groups=['base.group_system'])
|
||||
|
||||
|
||||
@http.route(['/website_version/all_versions_all_goals'], type = 'json', auth = "public", 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(int(view_id))
|
||||
website_id = request.website.id
|
||||
r1 = version.search_read([('website_id','=',website_id),'|',('view_ids.key','=',v.key),('view_ids.key','=','website.footer_default')],['id','name'])
|
||||
r2 = goal.search_read([],['id','name'])
|
||||
#Check if all the parameters are set to communicate with Google analytics
|
||||
if icp.get_param('google_%s_token' % 'management'):
|
||||
r3 = 2
|
||||
if request.website.google_analytics_key and request.website.google_analytics_view_id:
|
||||
r3 = 1
|
||||
else:
|
||||
r3 = 0
|
||||
return {'tab_version':r1, 'tab_goal':r2, 'check_conf': r3}
|
||||
|
||||
def check_view(self, version_ids):
|
||||
#Check if version_ids don't overlap with running experiments
|
||||
version_keys = set([v['key'] for v in request.env['ir.ui.view'].search_read([('version_id', 'in', version_ids)], ['key'])])
|
||||
exp_mod = request.env['website_version.experiment']
|
||||
exps = exp_mod.search([('state','=','running'),('website_id','=',request.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 (False,exp.name)
|
||||
return (True,"")
|
||||
|
||||
@http.route(['/website_version/launch_experiment'], type = 'json', auth = "public", website = True)
|
||||
def launch_experiment(self, name, version_ids, objectives):
|
||||
tab = []
|
||||
check = self.check_view(version_ids)
|
||||
if check[0]:
|
||||
for x in version_ids:
|
||||
tab.append([0, False, {'frequency': '50', 'version_id': int(x)}])
|
||||
vals = {'name':name, 'google_id': False, 'state': 'running', 'website_id':request.context.get('website_id'), 'experiment_version_ids':tab, 'objectives': int(objectives)}
|
||||
exp_obj = request.env['website_version.experiment']
|
||||
exp_obj.create(vals)
|
||||
return check
|
||||
|
||||
@http.route('/website/customize_template_get', type='json', auth='user', website=True)
|
||||
def customize_template_get(self, key, full=False, bundles=False, **kw):
|
||||
result = Website.customize_template_get(self, 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
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,158 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,7 @@
|
||||
import ir_ui_view
|
||||
import version
|
||||
import website
|
||||
import experiment
|
||||
import ir_qweb
|
||||
import res_config
|
||||
import ir_http
|
||||
@@ -0,0 +1,310 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from openerp.exceptions import Warning
|
||||
from openerp import SUPERUSER_ID
|
||||
from datetime import datetime, timedelta
|
||||
from openerp.osv import osv, fields
|
||||
import simplejson
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class Experiment_version(osv.Model):
|
||||
_name = "website_version.experiment_version"
|
||||
|
||||
#To get the index of the version of an experiment(Google analytics needs this information)
|
||||
def _get_index(self, cr, uid, ids, name, arg, context=None):
|
||||
result = {}
|
||||
for exp_ver in self.browse(cr, uid, ids, context=context):
|
||||
exp = exp_ver.experiment_id
|
||||
index = 1
|
||||
for x in exp.experiment_version_ids:
|
||||
if x.id == exp_ver.id:
|
||||
break
|
||||
else:
|
||||
index+=1
|
||||
result[exp_ver.id] = index
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'version_id': fields.many2one('website_version.version',string="version_id",required=True ,ondelete='cascade'),
|
||||
'experiment_id': fields.many2one('website_version.experiment',string="Experiment_id",required=True,ondelete='cascade'),
|
||||
'frequency': fields.selection([('10','Less'),('50','Medium'),('80','More')], 'Frequency'),
|
||||
'google_index': fields.function(_get_index,type='integer', string='Google_index'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'frequency': '50',
|
||||
}
|
||||
|
||||
#This model allow to define the Google analytics goals in a experiment
|
||||
class Goals(osv.Model):
|
||||
_name = "website_version.goals"
|
||||
|
||||
_columns = {
|
||||
'name': fields.char(string="Name", size=256, required=True),
|
||||
'google_ref': fields.char(string="Reference Google", size=256, required=True),
|
||||
}
|
||||
|
||||
EXPERIMENT_STATES = [('running','Running'),('paused','Paused'),('ended','Ended')]
|
||||
|
||||
class Experiment(osv.Model):
|
||||
_name = "website_version.experiment"
|
||||
_inherit = ['mail.thread']
|
||||
|
||||
def _get_version_number(self, cr, uid, ids, name, arg, context=None):
|
||||
result = {}
|
||||
for exp in self.browse(cr, uid, ids, context=context):
|
||||
result[exp.id] = 0
|
||||
for exp_ver in exp.experiment_version_ids:
|
||||
result[exp.id] += 1
|
||||
#For master
|
||||
result[exp.id] += 1
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name': fields.char(string="Title", size=256, required=True),
|
||||
'experiment_version_ids': fields.one2many('website_version.experiment_version', 'experiment_id',string="experiment_version_ids"),
|
||||
'website_id': fields.many2one('website',string="Website", required=True),
|
||||
'state': fields.selection(EXPERIMENT_STATES, 'Status', required=True, copy=False, track_visibility='onchange'),
|
||||
'objectives': fields.many2one('website_version.goals',string="Objective", required=True),
|
||||
'color': fields.integer('Color Index'),
|
||||
'version_number' : fields.function(_get_version_number,type='integer'),
|
||||
'sequence': fields.integer('Sequence', required=True, help="Test."),
|
||||
'google_id': fields.char(string="Google_id", size=256),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'state': 'running',
|
||||
'sequence': 1,
|
||||
}
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
exp={}
|
||||
exp['name'] = vals['name']
|
||||
exp['objectiveMetric'] = self.pool['website_version.goals'].browse(cr, uid, [vals['objectives']],context)[0].google_ref
|
||||
exp['status'] = vals['state']
|
||||
exp['variations'] =[{'name':'master','url': 'http://localhost/master'}]
|
||||
version_list = vals.get('experiment_version_ids')
|
||||
if version_list:
|
||||
for version in version_list:
|
||||
name = self.pool['website_version.version'].browse(cr, uid, [version[2]['version_id']],context)[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(_("You must select at least one version in your experiment."))
|
||||
google_id = self.pool['google.management'].create_an_experiment(cr, uid, exp, vals['website_id'], context=context)
|
||||
if not google_id:
|
||||
raise Warning(_("Please verify you give the authorizations to use google analytics api ..."))
|
||||
vals['google_id'] = google_id
|
||||
return super(Experiment, self).create(cr, uid, vals, context=context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
state = vals.get('state')
|
||||
for exp in self.browse(cr, uid, ids, context=context):
|
||||
if state and exp.state == 'ended':
|
||||
raise Warning(_("You cannot modify an ended experiment."))
|
||||
elif state == 'ended':
|
||||
#temp is the data to send to Googe
|
||||
temp={}
|
||||
temp['name'] = exp.name
|
||||
temp['status'] = state
|
||||
temp['variations'] = [{'name':'master','url': 'http://localhost/master'}]
|
||||
for exp_v in exp.experiment_version_ids:
|
||||
temp['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.pool['google.management'].update_an_experiment(cr, uid, temp, exp.google_id, exp.website_id.id, context=context)
|
||||
return super(Experiment, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
for exp in self.browse(cr, uid, ids, context=context):
|
||||
self.pool['google.management'].delete_an_experiment(cr, uid, exp.google_id, exp.website_id.id, context=context)
|
||||
return super(Experiment, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
def update_goals(self,cr,uid,ids,context=None):
|
||||
gm_obj = self.pool['google.management']
|
||||
goals_obj = self.pool['website_version.goals']
|
||||
website_id = context.get('website_id')
|
||||
if not website_id:
|
||||
raise Warning("You must specify the website.")
|
||||
x = gm_obj.get_goal_info(cr, uid, website_id, context=context)
|
||||
for y in x[1]['items']:
|
||||
if not goals_obj.search(cr, uid, [('name','=',y['name'])],context=context):
|
||||
vals ={'name':y['name'], 'google_ref':'ga:goal'+y['id']+'Completions'}
|
||||
goals_obj.create(cr, uid, vals, context=None)
|
||||
|
||||
def _check_view(self, cr, uid, ids, context=None):
|
||||
#No overlap for running experiments
|
||||
exp_ids = self.search(cr,uid,[('state','=','running')],context=context)
|
||||
exps = self.browse(cr,uid,exp_ids,context=context)
|
||||
check_a = set()
|
||||
check_b = set()
|
||||
for exp in exps:
|
||||
for exp_ver in exp.experiment_version_ids:
|
||||
for view in exp_ver.version_id.view_ids:
|
||||
x = (view.key,view.website_id.id)
|
||||
#the versions in the same experiment can have common keys
|
||||
y = (view.key,view.website_id.id,exp_ver.experiment_id.id)
|
||||
if x in check_a and not y in check_b:
|
||||
return False
|
||||
else:
|
||||
check_a.add(x)
|
||||
check_b.add(y)
|
||||
return True
|
||||
|
||||
def _check_website(self, cr, uid, ids, context=None):
|
||||
for exp in self.browse(cr,uid,ids,context=context):
|
||||
for exp_ver in exp.experiment_version_ids:
|
||||
if not exp_ver.version_id.website_id.id == exp.website_id.id:
|
||||
return False
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(_check_view, _('This experiment contains a view which is already used in another running experience'), ['state']),
|
||||
(_check_website, _('This experiment must have versions which are in the same website'), ['website_id', 'experiment_version_ids']),
|
||||
]
|
||||
|
||||
_order = 'sequence'
|
||||
|
||||
_group_by_full = {
|
||||
'state': lambda *args, **kwargs : ([s[0] for s in EXPERIMENT_STATES], dict()),
|
||||
}
|
||||
|
||||
class google_management(osv.AbstractModel):
|
||||
STR_SERVICE = 'management'
|
||||
|
||||
_name = 'google.%s' % STR_SERVICE
|
||||
|
||||
def generate_data(self, cr, uid, experiment, isCreating=False, context=None):
|
||||
|
||||
data = {
|
||||
'name': experiment['name'],
|
||||
'status': experiment['status'],
|
||||
'variations': experiment['variations']
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
def create_an_experiment(self, cr, uid, data, website_id, context=None):
|
||||
gs_pool = self.pool['google.service']
|
||||
website = self.pool['website'].browse(cr, uid, website_id, context=context)[0]
|
||||
webPropertyId = website.google_analytics_key
|
||||
if not webPropertyId:
|
||||
raise Warning(_("You must give a Google Analytics Key."))
|
||||
accountId = webPropertyId.split('-')[1]
|
||||
profileId = website.google_analytics_view_id
|
||||
if not profileId:
|
||||
raise Warning(_("You must give a Google view ID."))
|
||||
url = '/analytics/v3/management/accounts/%s/webproperties/%s/profiles/%s/experiments?access_token=%s' % (accountId, webPropertyId, profileId, self.get_token(cr, uid, context))
|
||||
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
|
||||
data_json = simplejson.dumps(data)
|
||||
try:
|
||||
x = gs_pool._do_request(cr, uid, url, data_json, headers, type='POST', context=context)
|
||||
except:
|
||||
x = False
|
||||
return x[1]['id']
|
||||
|
||||
def update_an_experiment(self, cr, uid, data, google_id, website_id, context=None):
|
||||
gs_pool = self.pool['google.service']
|
||||
website = self.pool['website'].browse(cr, uid, website_id, context=context)[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(cr, uid, context))
|
||||
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
|
||||
data_json = simplejson.dumps(data)
|
||||
|
||||
return gs_pool._do_request(cr, uid, url, data_json, headers, type='PUT', context=context)
|
||||
|
||||
def get_experiment_info(self, cr, uid, google_id, website_id, context=None):
|
||||
gs_pool = self.pool['google.service']
|
||||
website = self.pool['website'].browse(cr, uid, website_id, context=context)[0]
|
||||
webPropertyId = website.google_analytics_key
|
||||
accountId = webPropertyId.split('-')[1]
|
||||
profileId = website.google_analytics_view_id
|
||||
|
||||
params = {
|
||||
'access_token': self.get_token(cr, uid, context),
|
||||
}
|
||||
|
||||
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(cr, uid, url, params, headers, type='GET', context=context)
|
||||
|
||||
def get_goal_info(self, cr, uid, website_id, context=None):
|
||||
gs_pool = self.pool['google.service']
|
||||
website = self.pool['website'].browse(cr, uid, website_id, context=context)[0]
|
||||
webPropertyId = website.google_analytics_key
|
||||
accountId = webPropertyId.split('-')[1]
|
||||
profileId = website.google_analytics_view_id
|
||||
|
||||
params = {
|
||||
'access_token': self.get_token(cr, uid, context),
|
||||
}
|
||||
|
||||
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(cr, uid, url, params, headers, type='GET', context=context)
|
||||
|
||||
def delete_an_experiment(self, cr, uid, google_id, website_id, context=None):
|
||||
gs_pool = self.pool['google.service']
|
||||
website = self.pool['website'].browse(cr, uid, website_id, context=context)[0]
|
||||
webPropertyId = website.google_analytics_key
|
||||
accountId = webPropertyId.split('-')[1]
|
||||
profileId = website.google_analytics_view_id
|
||||
params = {
|
||||
'access_token': self.get_token(cr, uid, context)
|
||||
}
|
||||
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(cr, uid, url, params, headers, type='DELETE', context=context)
|
||||
|
||||
def get_token(self, cr, uid, context=None):
|
||||
icp = self.pool['ir.config_parameter']
|
||||
validity = icp.get_param(cr, SUPERUSER_ID, 'google_%s_token_validity' % self.STR_SERVICE)
|
||||
token = icp.get_param(cr, SUPERUSER_ID, '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(cr, uid, context=context)
|
||||
return token
|
||||
|
||||
def do_refresh_token(self, cr, uid, context=None):
|
||||
gs_pool = self.pool['google.service']
|
||||
icp = self.pool['ir.config_parameter']
|
||||
|
||||
rtoken = icp.get_param(cr, SUPERUSER_ID, 'google_%s_rtoken' % self.STR_SERVICE)
|
||||
all_token = gs_pool._refresh_google_token_json(cr, uid, rtoken, self.STR_SERVICE, context=context)
|
||||
|
||||
icp.set_param(cr, SUPERUSER_ID, 'google_%s_token_validity' % self.STR_SERVICE, datetime.now() + timedelta(seconds=all_token.get('expires_in')))
|
||||
icp.set_param(cr, SUPERUSER_ID, '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'
|
||||
|
||||
def authorize_google_uri(self, cr, uid, from_url='http://www.odoo.com', context=None):
|
||||
url = self.pool['google.service']._get_authorize_uri(cr, uid, from_url, self.STR_SERVICE, scope=self.get_management_scope(), context=context)
|
||||
return url
|
||||
|
||||
# convert code from authorize into token
|
||||
def set_all_tokens(self, cr, uid, authorization_code, context=None):
|
||||
gs_pool = self.pool['google.service']
|
||||
all_token = gs_pool._get_google_token_json(cr, uid, authorization_code, self.STR_SERVICE, context=context)
|
||||
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.pool['ir.config_parameter']
|
||||
icp.set_param(cr, SUPERUSER_ID, 'google_%s_rtoken' % self.STR_SERVICE, all_token.get('refresh_token'))
|
||||
icp.set_param(cr, SUPERUSER_ID, 'google_%s_token_validity' % self.STR_SERVICE, datetime.now() + timedelta(seconds=all_token.get('expires_in')))
|
||||
icp.set_param(cr, SUPERUSER_ID, 'google_%s_token' % self.STR_SERVICE, all_token.get('access_token'))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# -*- 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
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# -*- 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.addons.base.ir.ir_qweb import QWebContext
|
||||
from openerp.osv import osv, orm, fields
|
||||
|
||||
|
||||
class QWeb(orm.AbstractModel):
|
||||
""" QWeb object for rendering stuff in the website context
|
||||
"""
|
||||
_inherit = 'website.qweb'
|
||||
|
||||
def render(self, cr, uid, id_or_xml_id, qwebcontext=None, loader=None, context=None):
|
||||
if qwebcontext is None:
|
||||
qwebcontext = {}
|
||||
|
||||
if not isinstance(qwebcontext, QWebContext):
|
||||
qwebcontext = QWebContext(cr, uid, qwebcontext, loader=loader, context=context)
|
||||
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 'version_id' in context:
|
||||
version_id=context.get('version_id')
|
||||
if version_id:
|
||||
id_or_xml_id=self.pool["ir.ui.view"].search(cr, uid, [('key', '=', id_or_xml_id), '|', ('version_id', '=', False), ('version_id', '=', version_id), '|',('website_id','=',website_id),('website_id','=',False)], order='website_id, version_id', limit=1, context=context)[0]
|
||||
else:
|
||||
id_or_xml_id=self.pool["ir.ui.view"].search(cr, uid, [('key', '=', id_or_xml_id), ('version_id', '=', False), '|',('website_id','=',website_id),('website_id','=',False)], order='website_id', limit=1, context=context)[0]
|
||||
else:
|
||||
id_or_xml_id=self.pool["ir.ui.view"].search(cr, uid, [('key', '=', id_or_xml_id), '|', ('website_id','=',website_id),('website_id','=',False),('version_id', '=', False)], order='website_id', limit=1, context=context)[0]
|
||||
|
||||
|
||||
|
||||
qwebcontext['__template__'] = id_or_xml_id
|
||||
stack = qwebcontext.get('__stack__', [])
|
||||
if stack:
|
||||
qwebcontext['__caller__'] = stack[-1]
|
||||
stack.append(id_or_xml_id)
|
||||
qwebcontext['__stack__'] = stack
|
||||
qwebcontext['xmlid'] = str(stack[0]) # Temporary fix
|
||||
return self.render_node(self.get_template(id_or_xml_id, qwebcontext), qwebcontext)
|
||||
@@ -0,0 +1,173 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp.osv import osv,fields
|
||||
from openerp.http import request
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from openerp import tools
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
|
||||
class view(osv.Model):
|
||||
_inherit = "ir.ui.view"
|
||||
|
||||
_columns = {
|
||||
'version_id' : fields.many2one('website_version.version',ondelete='cascade', string="version_id"),
|
||||
}
|
||||
|
||||
def write(self, cr, uid, ids, vals, toggle=False, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
try:
|
||||
iter(ids)
|
||||
except:
|
||||
ids=[ids]
|
||||
|
||||
version_id=context.get('version_id')
|
||||
#toggle is true when changing active field
|
||||
if version_id and not context.get('mykey') and not toggle:
|
||||
ctx = dict(context, write_on_view=True)
|
||||
snap = self.pool['website_version.version']
|
||||
version=snap.browse(cr, uid, [version_id], context=ctx)[0]
|
||||
website_id=version.website_id.id
|
||||
version_view_ids = []
|
||||
for current in self.browse(cr, uid, ids, context=context):
|
||||
#check if current is in version
|
||||
if current.version_id.id == version_id:
|
||||
version_view_ids.append(current.id)
|
||||
else:
|
||||
new_id = self.search(cr, uid, [('website_id', '=', website_id),('version_id', '=', version_id), ('key', '=', current.key)], context=context)
|
||||
if new_id:
|
||||
version_view_ids.append(new_id[0])
|
||||
else:
|
||||
copy_id=self.copy(cr,uid, current.id,{'version_id':version_id, 'website_id':website_id},context=ctx)
|
||||
version_view_ids.append(copy_id)
|
||||
super(view, self).write(cr, uid, version_view_ids, vals, context=ctx)
|
||||
else:
|
||||
ctx = dict(context, write_on_view=True)
|
||||
super(view, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
#To make a version of a version
|
||||
def copy_version(self,cr, uid, version_id,new_version_id, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
ctx = dict(context, mykey=True)
|
||||
snap = self.pool['website_version.version']
|
||||
version=snap.browse(cr, uid, [version_id],ctx)[0]
|
||||
for view in version.view_ids:
|
||||
copy_id=self.copy(cr,uid,view.id,{'version_id':new_version_id},context=ctx)
|
||||
|
||||
def publish(self, cr, uid, ids, context=None):
|
||||
del_l = []
|
||||
views = self.browse(cr, uid, ids, context)
|
||||
for view in views:
|
||||
#To delete and replace views which are in the website( in fact with website_id)
|
||||
master_id = self.pool['ir.ui.view'].search(cr, uid, [('key','=',view.key),('version_id', '=', False),('website_id', '=', view.website_id.id)],context=context)
|
||||
del_l += master_id
|
||||
if del_l:
|
||||
self.pool['ir.ui.view'].unlink(cr, uid, del_l, context=context)
|
||||
for view in views:
|
||||
view.copy({'version_id': None})
|
||||
|
||||
|
||||
#To publish a view in backend
|
||||
def action_publish(self,cr,uid,ids,context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
ctx = dict(context, mykey=True)
|
||||
view_id = context.get('active_id')
|
||||
self.publish(cr,uid, [view_id], context=None)
|
||||
|
||||
def get_view_id(self, cr, uid, xml_id, context=None):
|
||||
if context and 'website_id' in context and not isinstance(xml_id, (int, long)):
|
||||
domain = [('key', '=', xml_id), '|', ('website_id', '=', context['website_id']), ('website_id', '=', False)]
|
||||
[xml_id] = self.search(cr, uid, domain, order='website_id', limit=1, context=context)
|
||||
else:
|
||||
xml_id = super(view, self).get_view_id(cr, uid, xml_id, context=context)
|
||||
return xml_id
|
||||
|
||||
|
||||
_read_template_cache = dict(accepted_keys=('lang', 'inherit_branding', 'editable', 'translatable', 'website_id','version_id'))
|
||||
|
||||
@tools.ormcache_context(**_read_template_cache)
|
||||
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
|
||||
|
||||
@tools.ormcache(size=0)
|
||||
def read_template(self, cr, uid, xml_id, context=None):
|
||||
if isinstance(xml_id, (int, long)):
|
||||
view_id = xml_id
|
||||
else:
|
||||
if '.' not in xml_id:
|
||||
raise ValueError('Invalid template id: %r' % (xml_id,))
|
||||
view_id = self.get_view_id(cr, uid, xml_id, context=context)
|
||||
return self._read_template(cr, uid, view_id, context=context)
|
||||
|
||||
def clear_cache(self):
|
||||
self._read_template.clear_cache(self)
|
||||
#self.get_view_id.clear_cache(self)
|
||||
|
||||
#To take the right inheriting views
|
||||
def get_inheriting_views_arch(self, cr, uid, view_id, model, context=None):
|
||||
arch = super(view, self).get_inheriting_views_arch(cr, uid, view_id, model, context=context)
|
||||
v = self.browse(cr, uid, [view_id],context)[0]
|
||||
if not (context and context.get('website_id') and v.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.read(cr, uid, view_arch.keys(), ['key','version_id','website_id'], context)
|
||||
for k in keys:
|
||||
#The view to take depends of the context
|
||||
if context.get('version_id'):
|
||||
#priority:1 take the view which is in the same version
|
||||
if k['version_id'] and k['version_id'][0] == context.get('version_id'):
|
||||
right_ids[k['key']] = k['id']
|
||||
priority[k['key']] = 3
|
||||
#priority:2 take the view which is just in the same website
|
||||
elif k['version_id'] == False and k['website_id'] and k['website_id'][0] == context.get('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 take the original view
|
||||
elif k['version_id'] == False and k['website_id'] == False:
|
||||
if not priority.get(k['key']) or priority.get(k['key']) < 2:
|
||||
right_ids[k['key']] = k['id']
|
||||
priority[k['key']] = 1
|
||||
else:
|
||||
#priority:1 take the view which is just in the same website
|
||||
if k['version_id'] == False and k['website_id'] and k['website_id'][0] == context.get('website_id'):
|
||||
right_ids[k['key']] = k['id']
|
||||
priority[k['key']] = 2
|
||||
#priority:2 take the original view
|
||||
elif k['version_id'] == False and k['website_id'] == 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}, toggle=True)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
from openerp.osv import fields, osv
|
||||
|
||||
class analytics_config_settings(osv.TransientModel):
|
||||
_inherit = 'base.config.settings'
|
||||
|
||||
_columns = {
|
||||
'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')
|
||||
}
|
||||
|
||||
def set_analytics(self,cr,uid,ids,context=None) :
|
||||
params = self.pool['ir.config_parameter']
|
||||
myself = self.browse(cr,uid,ids[0],context=context)
|
||||
params.set_param(cr, uid, 'google_management_client_id', myself.ga_client_id or '', groups=['base.group_system'], context=None)
|
||||
params.set_param(cr, uid, 'google_management_client_secret', myself.ga_client_secret or '', groups=['base.group_system'], context=None)
|
||||
|
||||
|
||||
def get_analytics(self,cr,uid,ids,context=None):
|
||||
params = self.pool.get('ir.config_parameter')
|
||||
ga_client_id = params.get_param(cr, uid, 'google_management_client_id',default='',context=context)
|
||||
ga_client_secret = params.get_param(cr, uid, 'google_management_client_secret',default='',context=context)
|
||||
return dict(ga_client_id=ga_client_id,ga_client_secret=ga_client_secret)
|
||||
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.exceptions import Warning
|
||||
from openerp.http import request
|
||||
from openerp.tools.translate import _
|
||||
|
||||
class version(osv.Model):
|
||||
_name = "website_version.version"
|
||||
|
||||
_columns = {
|
||||
'name' : fields.char(string="Title", required=True),
|
||||
'view_ids': fields.one2many('ir.ui.view', 'version_id',string="view_ids",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!')),
|
||||
]
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
Exp = self.pool['website_version.experiment']
|
||||
result = Exp.search(cr, uid, ['|',('state','=','running'),('state','=','paused'),('experiment_version_ids.version_id', 'in', ids)],context=context)
|
||||
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(cr, uid, ids, context=context)
|
||||
|
||||
def action_publish(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
version_id = context.get('active_id')
|
||||
if version_id:
|
||||
view_ids = self.pool['ir.ui.view'].search(cr, uid, [('version_id','=',version_id)], context=context)
|
||||
if view_ids:
|
||||
self.pool['ir.ui.view'].publish(cr,uid, view_ids, context=context)
|
||||
|
||||
def publish_version(self, cr, uid, version_id, save_master, copy_master_name, context = None):
|
||||
#Info: there were some cache problems with browse, this is why the code is so long
|
||||
version = self.browse(cr, uid, [int(version_id)],context)[0]
|
||||
del_l = []
|
||||
copy_l = []
|
||||
for view in version.view_ids:
|
||||
master_id = self.pool['ir.ui.view'].search(cr, uid, [('key','=',view.key),('version_id', '=', False),('website_id', '=', view.website_id.id)],context=context)
|
||||
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 = self.pool['ir.ui.view'].search(cr, uid, [('key','=',view.key),('version_id', '=', False),('website_id', '=', False)],context=context)
|
||||
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(cr, uid, [('name','=', copy_master_name),('website_id', '=', version.website_id.id)],context=context)
|
||||
#If it already exists, we delete the old to make the new
|
||||
if check_id:
|
||||
self.unlink(cr, uid, check_id, context=context)
|
||||
copy_version_id = self.create(cr, uid, {'name' : copy_master_name, 'website_id' : version.website_id.id}, context=context)
|
||||
for view in request.registry['ir.ui.view'].browse(cr, uid, copy_l, context=context):
|
||||
view.copy({'version_id': copy_version_id, 'website_id' : version.website_id.id})
|
||||
#Here, instead of deleting all the views we can just change the version_id BUT I've got some cache problems
|
||||
self.pool['ir.ui.view'].unlink(cr, uid, del_l, context=context)
|
||||
#All the views in the version published are copied without version_id
|
||||
for view in self.browse(cr, uid, [int(version_id)],context).view_ids:
|
||||
view.copy({'version_id': None}, context=context)
|
||||
return version.name
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp.osv import osv,fields
|
||||
from openerp.http import request
|
||||
import random
|
||||
import json
|
||||
|
||||
|
||||
class NewWebsite(osv.Model):
|
||||
_inherit = "website"
|
||||
|
||||
_columns = {
|
||||
'tuto_sync': 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')
|
||||
}
|
||||
|
||||
def get_current_version(self,cr,uid,context=None):
|
||||
snap = request.registry['website_version.version']
|
||||
version_id = request.context.get('version_id')
|
||||
|
||||
if not version_id:
|
||||
request.context['version_id'] = 0
|
||||
return (0, '')
|
||||
return snap.name_get(cr, uid, [version_id], context=context)[0];
|
||||
|
||||
def get_current_website(self, cr, uid, context=None):
|
||||
website = super(NewWebsite,self).get_current_website(cr, uid, context=context)
|
||||
#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', {})
|
||||
exp_ids = self.pool["website_version.experiment"].search(cr, uid, [('state','=','running'),('website_id.id','=',website.id)], context=context)
|
||||
exps = self.pool["website_version.experiment"].browse(cr, uid, exp_ids, context=context)
|
||||
for exp in exps:
|
||||
if not str(exp.google_id) in EXP:
|
||||
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[str(exp.google_id)] = str(0)
|
||||
x = random.randint(0,pond_sum-1)
|
||||
for res in result:
|
||||
if x<res[0]:
|
||||
EXP[str(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.pool['res.users'].has_group(cr, uid, 'base.group_website_publisher'):
|
||||
request.context['version_id'] = 0
|
||||
else:
|
||||
request.context['experiment_id'] = 1
|
||||
return website
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
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
|
||||
|
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,48 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 513 KiB |
@@ -0,0 +1,7 @@
|
||||
@charset "utf-8";
|
||||
|
||||
img.analytics_img_tuto {
|
||||
margin-left : 50px;
|
||||
margin-bottom : 10px;
|
||||
border: 2px solid grey;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
.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;
|
||||
}
|
||||
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 32 KiB |
@@ -0,0 +1,82 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
var hash = "#advanced-view-editor";
|
||||
var _t = openerp._t;
|
||||
|
||||
var website=openerp.website;
|
||||
|
||||
website.action= {};
|
||||
|
||||
website.EditorBar.include({
|
||||
start: function() {
|
||||
var self = this;
|
||||
var m_names = new Array("jan", "feb", "mar",
|
||||
"apr", "may", "jun", "jul", "aug", "sep",
|
||||
"oct", "nov", "dec");
|
||||
this.$el.on('click', '#save_as_new_version', function() {
|
||||
var d = new Date();
|
||||
var curr_date = d.getDate();
|
||||
var curr_month = d.getMonth();
|
||||
var curr_year = d.getFullYear();
|
||||
|
||||
website.prompt({
|
||||
id: "editor_new_version",
|
||||
window_title: _t("New version"),
|
||||
input: "Version name" ,
|
||||
default :(curr_date + " " + m_names[curr_month] + " " + curr_year),
|
||||
}).then(function (name) {
|
||||
var context = website.get_context();
|
||||
openerp.jsonRpc( '/website_version/create_version', 'call', { 'name': name, 'version_id': 0 }).then(function (result) {
|
||||
$('html').data('version_id', result);
|
||||
|
||||
var wizard = $(openerp.qweb.render("website_version.message",{message:_.str.sprintf("You are actually working on %s version.", name)}));
|
||||
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 = $(openerp.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();});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
this.$el.on('click', '#save_and_publish', function() {
|
||||
var version_id = $('html').data('version_id');
|
||||
if(version_id)
|
||||
{
|
||||
self.save();
|
||||
}
|
||||
else
|
||||
{
|
||||
var wizard = $(openerp.qweb.render("website_version.delete_message",{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(openerp.qweb.render("all_options", {version:'Save on '+name}));
|
||||
}
|
||||
else{
|
||||
self.$el.find(".o_first_choice").before(openerp.qweb.render("all_options", {version:'Save and Publish'}));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return this._super();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,287 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
var _t = openerp._t;
|
||||
|
||||
var website=openerp.website;
|
||||
var QWeb = openerp.qweb;
|
||||
website.add_template_file('/website_version/static/src/xml/version_templates.xml');
|
||||
|
||||
website.EditorVersion = openerp.Widget.extend({
|
||||
start: function() {
|
||||
var self = this;
|
||||
|
||||
$('html').data('version_id', this.$el.find("#version-menu-button").data("version_id"));
|
||||
var _get_context = website.get_context;
|
||||
website.get_context = function (dict) {
|
||||
return _.extend({ 'version_id': $('html').data('version_id') }, _get_context(dict));
|
||||
};
|
||||
|
||||
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 = $('html').attr('data-view-xmlid');
|
||||
openerp.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("all_versions", {versions:result}));
|
||||
|
||||
});
|
||||
openerp.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("experiment_menu"));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
return this._super();
|
||||
},
|
||||
|
||||
duplicate_version: function(event) {
|
||||
var version_id = $('html').data('version_id');
|
||||
if(!version_id){
|
||||
version_id = 0;
|
||||
}
|
||||
var m_names = new Array("jan", "feb", "mar",
|
||||
"apr", "may", "jun", "jul", "aug", "sep",
|
||||
"oct", "nov", "dec");
|
||||
var d = new Date();
|
||||
var curr_date = d.getDate();
|
||||
var curr_month = d.getMonth();
|
||||
var curr_year = d.getFullYear();
|
||||
website.prompt({
|
||||
id: "editor_new_version",
|
||||
window_title: _t("New version"),
|
||||
input: "Version name" ,
|
||||
default :(curr_date + " " + m_names[curr_month] + " " + curr_year),
|
||||
}).then(function (name) {
|
||||
openerp.jsonRpc( '/website_version/create_version', 'call', { 'name': name, 'version_id': version_id}).then(function (result) {
|
||||
|
||||
var wizard = $(openerp.qweb.render("website_version.message",{message:_.str.sprintf("You are actually working on %s version.", name)}));
|
||||
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 = $(openerp.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();});
|
||||
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
change_version: function(event) {
|
||||
var version_id = $(event.target).parent().data("version_id");
|
||||
if(! version_id){
|
||||
version_id = 0;//By default master
|
||||
}
|
||||
openerp.jsonRpc( '/website_version/change_version', 'call', { 'version_id':version_id }).then(function (result) {
|
||||
location.reload();
|
||||
});
|
||||
},
|
||||
|
||||
delete_version: function(event) {
|
||||
var version_id = $(event.currentTarget).parent().data("version_id");
|
||||
var name = $(event.currentTarget).parent().children(':last-child').text();
|
||||
openerp.jsonRpc( '/website_version/check_version', 'call', { 'version_id':version_id }).then(function (result) {
|
||||
if (result){
|
||||
var wizard = $(openerp.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 = $(openerp.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(){
|
||||
openerp.jsonRpc( '/website_version/delete_version', 'call', { 'version_id':version_id }).then(function (result) {
|
||||
var wizardB = $(openerp.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 = $('html').data('version_id');
|
||||
var name = $(event.currentTarget).parent().parent().parent().children().children(':first-child').text();
|
||||
openerp.jsonRpc( '/website_version/diff_version', 'call', { 'version_id':version_id}).then(function (result) {
|
||||
var wizardA = $(openerp.qweb.render("website_version.publish_message",{message:_.str.sprintf("Are you sure you want to publish the %s version ?", 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{
|
||||
openerp.jsonRpc( '/website_version/publish_version', 'call', { 'version_id':version_id, 'save_master':true, 'copy_master_name':copy_master_name}).then(function (result) {
|
||||
var wizardB = $(openerp.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{
|
||||
openerp.jsonRpc( '/website_version/publish_version', 'call', { 'version_id':version_id, 'save_master':false, 'copy_master_name':""}).then(function (result) {
|
||||
var wizardC = $(openerp.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 = $('html').data('version_id');
|
||||
var name = $('#version-menu-button').data('version_name');
|
||||
openerp.jsonRpc( '/website_version/diff_version', 'call', { 'version_id':version_id}).then(function (result) {
|
||||
var wizard = $(openerp.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 = $('html').attr('data-view-xmlid');
|
||||
openerp.jsonRpc( '/website_version/all_versions_all_goals', 'call', { 'view_id': view_id }).then(function (result) {
|
||||
var wizardA = $(openerp.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 objectives = 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){
|
||||
openerp.jsonRpc( '/website_version/launch_experiment', 'call', { 'name':name, 'version_ids':result, 'objectives':objectives }).then(function (result) {
|
||||
if (result[0]){
|
||||
var wizardB = $(openerp.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{
|
||||
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, result[1])+"</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(){
|
||||
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{
|
||||
openerp.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 = website.get_context();
|
||||
openerp.jsonRpc( '/website_version/google_access', 'call', {
|
||||
fromurl: window.location.href,
|
||||
local_context: context
|
||||
}).done(function(o) {
|
||||
if (o.status === "need_auth") {
|
||||
var wizardC = $(openerp.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(o) { $('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{
|
||||
openerp.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 website.EditorVersion();
|
||||
version.setElement($("#version-menu"));
|
||||
version.start();
|
||||
});
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,212 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var _t = openerp._t;
|
||||
|
||||
openerp.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[id="version-menu-button"]:contains("Version"):first',
|
||||
},
|
||||
{
|
||||
title: _t("Click on New version"),
|
||||
popover: { fixed: true },
|
||||
element: 'a[data-action="duplicate_version"]:contains("New Version"):first',
|
||||
},
|
||||
{
|
||||
title: _t("Give a version name"),
|
||||
content: _t("Give a clever name to retrieve it easily."),
|
||||
popover: { fixed: true },
|
||||
waitFor: '.modal button[type="button"]:contains("Continue")',
|
||||
element: '.modal input[type="text"]',
|
||||
sampleText: 'Test',
|
||||
},
|
||||
{
|
||||
title: _t("Validate the version name"),
|
||||
popover: { fixed: true },
|
||||
element: '.modal button[type="button"]:contains("Continue")',
|
||||
},
|
||||
{
|
||||
title: _t("Confirm"),
|
||||
popover: { fixed: true },
|
||||
waitNot: '.modal button[type="button"]:contains("Continue")',
|
||||
element: '.modal button[type="button"]:contains("Ok")',
|
||||
},
|
||||
{
|
||||
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[type="button"]:contains("Ok")',
|
||||
},
|
||||
{
|
||||
title: _t("Click on Edit"),
|
||||
content: _t("Every page of your website can be modified through the <i>Edit</i> button."),
|
||||
waitFor: 'button[data-action="edit"]:contains("Edit")',
|
||||
element: 'button[data-action="edit"]:contains("Edit")',
|
||||
},
|
||||
{
|
||||
element: 'button[data-action=snippet]',
|
||||
placement: 'bottom',
|
||||
title: _t("Insert building blocks"),
|
||||
content: _t("Click here to insert blocks of content in the page."),
|
||||
popover: { fixed: true },
|
||||
},
|
||||
{
|
||||
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',
|
||||
popover: { next: _t("Continue") },
|
||||
},
|
||||
{
|
||||
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") },
|
||||
},
|
||||
{
|
||||
waitNot: '.popover.tour',
|
||||
element: 'button[data-action=snippet]',
|
||||
placement: 'bottom',
|
||||
title: _t("Add Another Block"),
|
||||
content: _t("Let's add another building block to your page."),
|
||||
popover: { fixed: true },
|
||||
},
|
||||
{
|
||||
snippet: '#snippet_structure .oe_snippet:eq(6)',
|
||||
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 },
|
||||
},
|
||||
{
|
||||
waitFor: 'button[data-action=save]:not(: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[id="version-menu-button"]:contains("Version"):first',
|
||||
popover: { fixed: true },
|
||||
},
|
||||
|
||||
{
|
||||
title: _t("Click on Publish Version"),
|
||||
element: 'a[data-action="publish_version"]:contains("Publish Version"):first',
|
||||
popover: { fixed: true },
|
||||
},
|
||||
|
||||
{
|
||||
title: _t("Click on Publish button"),
|
||||
//waitFor: '.modal button[type="button"]:contains("Publish")',
|
||||
element: '.modal button[type="button"]:contains("Publish")',
|
||||
placement: 'left',
|
||||
},
|
||||
|
||||
{
|
||||
title: _t("Confirm"),
|
||||
waitFor: '.modal button[type="button"]:contains("Ok")',
|
||||
element: '.modal button[type="button"]:contains("Ok")',
|
||||
popover: { fixed: true },
|
||||
},
|
||||
|
||||
|
||||
//3.
|
||||
{
|
||||
title: _t("Delete the version"),
|
||||
content: _t("Now we will delete the version you have just published."),
|
||||
waitNot: '.modal button[type="button"]:contains("Ok")',
|
||||
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
|
||||
},
|
||||
|
||||
{
|
||||
title: _t("Click on Version"),
|
||||
element: 'a[id="version-menu-button"]:contains("Version"):first',
|
||||
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"),
|
||||
waitFor: '.modal button[type="button"]:contains("Delete Version")',
|
||||
element: '.modal button[type="button"]:contains("Delete Version")',
|
||||
popover: { fixed: true },
|
||||
},
|
||||
|
||||
{
|
||||
title: _t("Confirm"),
|
||||
waitFor: '.modal button[type="button"]:contains("Ok")',
|
||||
element: '.modal button[type="button"]:contains("Ok")',
|
||||
popover: { fixed: true },
|
||||
},
|
||||
|
||||
{
|
||||
title: _t("Finish"),
|
||||
content: _t("Felicitation, now you are able to edit and manage your versions."),
|
||||
waitNot: '.modal button[type="button"]:contains("Ok")',
|
||||
},
|
||||
|
||||
]
|
||||
});
|
||||
|
||||
}());
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var instance = openerp;
|
||||
openerp.website_version = instance.website_version || {};
|
||||
|
||||
var module = instance.website_version;
|
||||
var QWeb = instance.web.qweb;
|
||||
var _t = openerp._t;
|
||||
|
||||
|
||||
instance.website_version.rtoken = instance.web.form.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 = instance.web.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!"));
|
||||
instance.web.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(o) { $('button.GoogleAccess').prop('disabled', false); });
|
||||
}
|
||||
|
||||
});
|
||||
instance.web.form.widgets.add('rtoken', 'openerp.website_version.rtoken');
|
||||
|
||||
|
||||
})();
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="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>
|
||||
<t t-if="item.bold == 0 ">
|
||||
<a href="#" data-action="change_version" t-att-data-version_id="item.id"><t t-esc="item.name"></t> </a>
|
||||
</t>
|
||||
<t t-if="item.bold == 1 ">
|
||||
<a href="#" data-action="change_version" t-att-data-version_id="item.id"> <b><t t-esc="item.name"></t></b> </a>
|
||||
</t>
|
||||
</li>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-extend="website.editorbar">
|
||||
<t t-jquery=".navbar-header 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="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="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">
|
||||
<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">
|
||||
<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>
|
||||
<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>
|
||||
<div class="o_configure_ab">
|
||||
<p>You must configure your account.</p>
|
||||
<p>To configure your account, you must have a google analytics account.</p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-if= "config == 2">
|
||||
<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>
|
||||
<div class="o_configure_ab">
|
||||
<p>You must configure your account.</p>
|
||||
<p>To configure your account, you must have a google analytics account.</p>
|
||||
</div>
|
||||
</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>
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<h4 class="modal-title">Diff between Master and <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><t t-esc="item"></t> </li>
|
||||
</t>
|
||||
</ul>
|
||||
</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">Ok</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">
|
||||
<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>
|
||||
<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">
|
||||
<h4 class="modal-title"><t t-esc="message"></t></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>When you publish a version, you erase some views in master. If you want to save the views that will be erased, you can save these views in a new version. Here is the list of master views which will be erased:</p>
|
||||
<t t-if="list.length != 0">
|
||||
<ul>
|
||||
<t t-foreach="list" t-as="item">
|
||||
<li><t t-esc="item"></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"/>
|
||||
Don't save Master
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="optionsRadios" id="optionsRadios2" value="option2" class="o_check"/>
|
||||
Save Master
|
||||
<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>
|
||||
</templates>
|
||||
@@ -0,0 +1,7 @@
|
||||
import test_ui
|
||||
|
||||
from . import test_website_version_all
|
||||
|
||||
checks = [
|
||||
test_website_version_all,
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
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("/", "openerp.Tour.run('versioning', 'test')", "openerp.Tour.tours.versioning", login='admin')
|
||||
@@ -0,0 +1,17 @@
|
||||
from . import test_website_version_base
|
||||
from openerp.osv.orm import except_orm
|
||||
from openerp.http import request
|
||||
|
||||
class TestWebsiteVersionAll(test_website_version_base.TestWebsiteVersionBase):
|
||||
|
||||
def test_copy_version(self):
|
||||
""" Testing version_copy"""
|
||||
cr, uid, view_0_0_0_0_id, version_id, website_id = self.cr, self.uid, self.view_0_0_0_0_id, self.version_id, self.website_id
|
||||
|
||||
copy_version_id = self.version.create(cr, uid,{'name':'copy_version_0_0_0_0', 'website_id':website_id}, context=None)
|
||||
self.ir_ui_view.copy_version(cr, uid, version_id,copy_version_id,context=None)
|
||||
copy_version = self.version.browse(cr, uid, [copy_version_id], context=None)[0]
|
||||
view_copy_version=copy_version.view_ids[0]
|
||||
view_0_0_0_0 = self.ir_ui_view.browse(cr, uid, [view_0_0_0_0_id], context={'version_id':version_id})[0]
|
||||
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')
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
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.registry('ir.ui.view')
|
||||
self.ir_qweb = self.registry('website.qweb')
|
||||
self.version = self.registry('website_version.version')
|
||||
self.website = self.registry('website')
|
||||
|
||||
#Usefull objects
|
||||
master_view_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'website', 'website2_homepage')
|
||||
self.master_view_id = master_view_ref and master_view_ref[1] or False
|
||||
self.arch_master=self.ir_ui_view.browse(cr, uid, [self.master_view_id], context=None)[0].arch
|
||||
version_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'website_version', 'version_0_0_0_0')
|
||||
self.version_id = version_ref and version_ref[1] or False
|
||||
website_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'website', 'website2')
|
||||
self.website_id = website_ref and website_ref[1] or False
|
||||
view_0_0_0_0_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'website_version', 'website2_homepage_other')
|
||||
self.view_0_0_0_0_id = view_0_0_0_0_ref and view_0_0_0_0_ref[1] or False
|
||||
self.arch_0_0_0_0 = self.ir_ui_view.browse(cr, uid, [self.view_0_0_0_0_id], context=None)[0].arch
|
||||
self.vals = {'arch':
|
||||
"""<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>"""
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
<?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="oe_dropdown_kanban">
|
||||
|
||||
<!-- dropdown menu -->
|
||||
<span class="oe_dropdown_toggle">
|
||||
<span class="oe_e">í</span>
|
||||
<ul class="oe_dropdown_menu">
|
||||
<li><a type="delete">Delete</a></li>
|
||||
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
|
||||
</ul>
|
||||
</span>
|
||||
</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="oe_stat_button 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="objectives"/>
|
||||
<div>
|
||||
<field name="objectives" 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="oe_stat_button pull-right"
|
||||
context="{'active_id': active_id}"/>
|
||||
</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="Website" id="website_menu" sequence="10" parent="base.marketing_menu" />
|
||||
<menuitem action="action_website_view" id="menu_website_view" parent="website_menu"/>
|
||||
<menuitem action="action_version" id="menu_action_version" parent="website_menu" groups="base.group_no_one"/>
|
||||
<menuitem action="action_experiment" id="menu_action_experiment" parent="website_menu"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,112 @@
|
||||
<?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">
|
||||
<div name="google_analytics" position="replace">
|
||||
<div>
|
||||
<div>
|
||||
<label for="ga_sync"/>
|
||||
<field name="ga_sync" class="oe_inline"/>
|
||||
<div>
|
||||
<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>
|
||||
</div>
|
||||
<group>
|
||||
<div class="analytics_settings">
|
||||
<group>
|
||||
<div>
|
||||
<label for="ga_client_id" string="Google Client ID" />
|
||||
<field name="ga_client_id" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<div>
|
||||
<label for="ga_client_secret" string="Google Client Secret"/>
|
||||
<field name="ga_client_secret" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<div>
|
||||
<field name="google_management_authorization" widget="rtoken"/>
|
||||
</div>
|
||||
</group>
|
||||
</div>
|
||||
</group>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
@@ -0,0 +1,79 @@
|
||||
<?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[contains(@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(context=context)[0]" t-att-data-version_name="website.get_current_version(context=context)[1]">
|
||||
Version
|
||||
<span><t t-esc="website.get_current_version(context=context)[1]"></t></span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu version_menu" role="menu">
|
||||
<li class="dropdown-header" style="text-transform: uppercase;">All versions</li>
|
||||
<t t-if="website.get_current_version(context=context)[0] == 0 ">
|
||||
<li><a href="#" data-action="change_version"><b>Master</b></a></li>
|
||||
</t>
|
||||
<t t-if="website.get_current_version(context=context)[0] != 0 ">
|
||||
<li><a href="#" data-action="change_version">Master</a></li>
|
||||
</t>
|
||||
<li class="first_divider divider"> </li>
|
||||
<t t-if="website.get_current_version(context=context)[0] == 0 ">
|
||||
<li><a href="#" data-action="duplicate_version">New Version</a></li>
|
||||
</t>
|
||||
<t t-if="website.get_current_version(context=context)[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">Diff with Master</a></li>
|
||||
</t>
|
||||
<li class="divider o_publish_version"> </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_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_frontend_AB" name="website_AB assets" inherit_id="website.layout">
|
||||
<xpath expr="//script[contains(@id, 'tracking_code')]" position="replace">
|
||||
<script id='tracking_code'>
|
||||
(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"/>'), {'cookieDomain': 'none'});
|
||||
ga('send','pageview');
|
||||
edit = $('html').attr('data-editable');
|
||||
if (edit != "1"){
|
||||
var view_id = $('html').attr('data-view-xmlid');
|
||||
openerp.jsonRpc( '/website_version/get_analytics', 'call', { 'view_id':view_id }).then(function (result) {
|
||||
var exp = result['ExpId'];
|
||||
var ver = result['VarId'];
|
||||
ga('set', 'expId', exp);
|
||||
ga('set', 'expVar', ver);
|
||||
ga('send', 'pageview');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</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>
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<?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_sync"/>
|
||||
<div colspan="4">
|
||||
<div attrs="{'invisible':[('tuto_sync','=',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 string="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>
|
||||
|
||||
<menuitem action="action_website_view" id="menu_website_view" parent="base.menu_res_company_global"/>
|
||||
|
||||
|
||||
<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"
|
||||
context="{'active_id': active_id}" attrs="{'invisible': ['|','|',('type', '!=', 'qweb'),('website_id', '=',False), ('version_id', '=', False)]}" />
|
||||
</group>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -193,6 +193,8 @@
|
||||
<rng:optional><rng:attribute name="forcecreate"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="context"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="priority"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="key"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="website_id"/></rng:optional>
|
||||
<rng:choice>
|
||||
<rng:group>
|
||||
<rng:optional>
|
||||
|
||||
@@ -751,6 +751,10 @@ form: module.record_id""" % (xml_id,)
|
||||
record.append(Field(el.get('priority', "16"), name='priority'))
|
||||
if 'inherit_id' in el.attrib:
|
||||
record.append(Field(name='inherit_id', ref=el.get('inherit_id')))
|
||||
if 'website_id' in el.attrib:
|
||||
record.append(Field(name='website_id', ref=el.get('website_id')))
|
||||
if 'key' in el.attrib:
|
||||
record.append(Field(el.get('key'), name='key'))
|
||||
if el.get('active') in ("True", "False"):
|
||||
view_id = self.id_get(cr, tpl_id, raise_if_not_found=False)
|
||||
if mode != "update" or not view_id:
|
||||
|
||||