summaryrefslogtreecommitdiff
path: root/addons/website
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-06-06 11:54:35 +0200
committerChristophe Simonis <chs@odoo.com>2019-06-06 11:54:35 +0200
commit71a50a2214748fec413c5a0f042d0e7172ae6ea9 (patch)
tree2e9ee11551350e23923390d9c53baf630b6ed834 /addons/website
parenta7621137cb0d75ec545152d5e1d413c9d3548e45 (diff)
parent409679866b2ee8352a8cb27460e7332563526924 (diff)
[MERGE] forward port branch saas-12.3 up to 409679866b2
Diffstat (limited to 'addons/website')
-rw-r--r--addons/website/models/res_users.py9
-rw-r--r--addons/website/models/website.py11
-rw-r--r--addons/website/static/src/js/content/snippets.animation.js4
-rw-r--r--addons/website/static/src/js/content/website_root.js31
-rw-r--r--addons/website/static/src/js/menu/seo.js62
-rw-r--r--addons/website/static/tests/tours/rte.js1
-rw-r--r--addons/website/tests/test_get_current_website.py7
-rw-r--r--addons/website/views/website_templates.xml23
8 files changed, 102 insertions, 46 deletions
diff --git a/addons/website/models/res_users.py b/addons/website/models/res_users.py
index a84eaaeb3c6..8902e4c34b6 100644
--- a/addons/website/models/res_users.py
+++ b/addons/website/models/res_users.py
@@ -2,8 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
-from odoo import api, fields, models, tools, _
-from odoo.exceptions import ValidationError
+from odoo import api, fields, models, tools
from odoo.http import request
_logger = logging.getLogger(__name__)
@@ -12,8 +11,8 @@ _logger = logging.getLogger(__name__)
class ResUsers(models.Model):
_inherit = 'res.users'
- website_id = fields.Many2one('website', related='partner_id.website_id', store=True, related_sudo=False, readonly=True)
-
+ website_id = fields.Many2one('website', related='partner_id.website_id', store=True, related_sudo=False, readonly=False)
+
_sql_constraints = [
# Partial constraint, complemented by unique index (see below). Still
# useful to keep because it provides a proper error message when a
@@ -51,7 +50,7 @@ class ResUsers(models.Model):
@api.model_cr_context
def _auto_init(self):
result = super(ResUsers, self)._auto_init()
- # Use unique index to implement unique constraint per website, even if website_id is null
+ # Use unique index to implement unique constraint per website, even if website_id is null
# (not possible using a constraint)
tools.create_unique_index(self._cr, 'res_users_login_key_unique_website_index',
self._table, ['login', 'COALESCE(website_id,-1)'])
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index bbc8489cf47..5202798fb97 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -149,14 +149,17 @@ class Website(models.Model):
@api.multi
def write(self, values):
+ public_user_to_change_websites = self.env['website']
self._handle_favicon(values)
self._get_languages.clear_cache(self)
if 'company_id' in values and 'user_id' not in values:
- company = self.env['res.company'].browse(values['company_id'])
- values['user_id'] = company._get_public_user().id
+ public_user_to_change_websites = self.filtered(lambda w: w.user_id.company_id.id != values['company_id'])
+ if public_user_to_change_websites:
+ company = self.env['res.company'].browse(values['company_id'])
+ super(Website, public_user_to_change_websites).write(dict(values, user_id=company._get_public_user().id))
- result = super(Website, self).write(values)
+ result = super(Website, self - public_user_to_change_websites).write(values)
if 'cdn_activated' in values or 'cdn_url' in values or 'cdn_filters' in values:
# invalidate the caches from static node at compile time
self.env['ir.qweb'].clear_caches()
@@ -185,6 +188,8 @@ class Website(models.Model):
self.homepage_id = self.env['website.page'].search([('website_id', '=', self.id),
('key', '=', standard_homepage.key)])
+ # prevent /-1 as homepage URL
+ self.homepage_id.url = '/'
# Bootstrap default menu hierarchy, create a new minimalist one if no default
default_menu = self.env.ref('website.main_menu')
diff --git a/addons/website/static/src/js/content/snippets.animation.js b/addons/website/static/src/js/content/snippets.animation.js
index 7f57eb81f2c..33e1e01ebcc 100644
--- a/addons/website/static/src/js/content/snippets.animation.js
+++ b/addons/website/static/src/js/content/snippets.animation.js
@@ -860,6 +860,10 @@ registry.gallerySlider = publicWidget.Widget.extend({
destroy: function () {
this._super.apply(this, arguments);
+ if (!this.$indicator) {
+ return;
+ }
+
this.$prev.prependTo(this.$indicator);
this.$next.appendTo(this.$indicator);
this.$carousel.off('.gallery_slider');
diff --git a/addons/website/static/src/js/content/website_root.js b/addons/website/static/src/js/content/website_root.js
index 22c71890643..612265124cd 100644
--- a/addons/website/static/src/js/content/website_root.js
+++ b/addons/website/static/src/js/content/website_root.js
@@ -19,6 +19,7 @@ var WebsiteRoot = publicRootData.PublicRoot.extend({
}),
custom_events: _.extend({}, publicRootData.PublicRoot.prototype.custom_events || {}, {
'ready_to_clean_for_save': '_onWidgetsStopRequest',
+ seo_object_request: '_onSeoObjectRequest',
}),
/**
@@ -111,6 +112,36 @@ var WebsiteRoot = publicRootData.PublicRoot.extend({
window.location.href = _.str.sprintf("/website/lang/%(lang)s?r=%(url)s%(hash)s", redirect);
},
/**
+ /**
+ * Checks information about the page SEO object.
+ *
+ * @private
+ * @param {OdooEvent} ev
+ */
+ _onSeoObjectRequest: function (ev) {
+ var res = this._unslugHtmlDataObject('seo-object');
+ ev.data.callback(res);
+ },
+ /**
+ * Returns a model/id object constructed from html data attribute.
+ *
+ * @private
+ * @param {string} dataAttr
+ * @returns {Object} an object with 2 keys: model and id, or null
+ * if not found
+ */
+ _unslugHtmlDataObject: function (dataAttr) {
+ var repr = $('html').data(dataAttr);
+ var match = repr && repr.match(/(.+)\((\d+),(.*)\)/);
+ if (!match) {
+ return null;
+ }
+ return {
+ model: match[1],
+ id: match[2] | 0,
+ };
+ },
+ /**
* @todo review
* @private
*/
diff --git a/addons/website/static/src/js/menu/seo.js b/addons/website/static/src/js/menu/seo.js
index 332fde71a4f..b65137ecc8f 100644
--- a/addons/website/static/src/js/menu/seo.js
+++ b/addons/website/static/src/js/menu/seo.js
@@ -129,17 +129,17 @@ var Keyword = Widget.extend({
_updateTitle: function () {
var $title = this.$('.js_seo_keyword_title');
if (this.htmlPage.isInTitle(this.keyword)) {
- $title.css('visibility','visible');
+ $title.css('visibility', 'visible');
} else {
- $title.css('visibility','hidden');
+ $title.css('visibility', 'hidden');
}
},
_updateDescription: function () {
var $description = this.$('.js_seo_keyword_description');
if (this.htmlPage.isInDescription(this.keyword)) {
- $description.css('visibility','visible');
+ $description.css('visibility', 'visible');
} else {
- $description.css('visibility','hidden');
+ $description.css('visibility', 'hidden');
}
},
});
@@ -210,7 +210,7 @@ var Preview = Widget.extend({
this.url = options.url;
this.description = options.description || _t("The description will be generated by search engines based on page content unless you specify one.");
if (this.description.length > 160) {
- this.description = this.description.substring(0,159) + '…';
+ this.description = this.description.substring(0, 159) + '…';
}
this._super(parent);
},
@@ -289,19 +289,19 @@ var HtmlPage = Class.extend(mixins.PropertiesMixin, {
return $('body').children().not('.oe_seo_configuration').find('h2').text();
},
isInBody: function (text) {
- return new RegExp(WORD_SEPARATORS_REGEX+text+WORD_SEPARATORS_REGEX, 'gi').test(this.bodyText());
+ return new RegExp(WORD_SEPARATORS_REGEX + text + WORD_SEPARATORS_REGEX, 'gi').test(this.bodyText());
},
isInTitle: function (text) {
- return new RegExp(WORD_SEPARATORS_REGEX+text+WORD_SEPARATORS_REGEX, 'gi').test(this.title());
+ return new RegExp(WORD_SEPARATORS_REGEX + text + WORD_SEPARATORS_REGEX, 'gi').test(this.title());
},
isInDescription: function (text) {
- return new RegExp(WORD_SEPARATORS_REGEX+text+WORD_SEPARATORS_REGEX, 'gi').test(this.description());
+ return new RegExp(WORD_SEPARATORS_REGEX + text + WORD_SEPARATORS_REGEX, 'gi').test(this.description());
},
isInHeading1: function (text) {
- return new RegExp(WORD_SEPARATORS_REGEX+text+WORD_SEPARATORS_REGEX, 'gi').test(this.heading1());
+ return new RegExp(WORD_SEPARATORS_REGEX + text + WORD_SEPARATORS_REGEX, 'gi').test(this.heading1());
},
isInHeading2: function (text) {
- return new RegExp(WORD_SEPARATORS_REGEX+text+WORD_SEPARATORS_REGEX, 'gi').test(this.heading2());
+ return new RegExp(WORD_SEPARATORS_REGEX + text + WORD_SEPARATORS_REGEX, 'gi').test(this.heading2());
},
});
@@ -415,7 +415,7 @@ var MetaTitleDescription = Widget.extend({
_renderPreview: function () {
var indexed = this.isIndexed;
var preview = "";
- if (indexed){
+ if (indexed) {
preview = new Preview(this, {
title: this.getTitle(),
description: this.getDescription(),
@@ -447,7 +447,7 @@ var MetaKeywords = Widget.extend({
start: function () {
var self = this;
this.$input = this.$('input[name=website_meta_keywords]');
- this.keywordList = new KeywordList(this, { htmlPage: this.htmlPage });
+ this.keywordList = new KeywordList(this, {htmlPage: this.htmlPage});
this.keywordList.on('list-full', this, function () {
self.$input.attr({
readonly: 'readonly',
@@ -494,7 +494,7 @@ var MetaKeywords = Widget.extend({
model: 'website',
method: 'get_languages',
args: [[context.website_id]],
- }).then( function (data) {
+ }).then(function (data) {
self.$('#language-box').html(core.qweb.render('Configurator.language_promote', {
'language': data,
'def_lang': context.lang
@@ -508,7 +508,7 @@ var MetaKeywords = Widget.extend({
* @param {boolean} removed: a keyword is about to be removed,
* we need to exclude it from the count
*/
- _updateTable : function (removed) {
+ _updateTable: function (removed) {
var min = removed ? 1 : 0;
if (this.keywordList.keywords().length > min) {
this.$('table').show();
@@ -562,7 +562,7 @@ var MetaImageSelector = Widget.extend({
_setDescription: function (description) {
this.metaDescription = description || _t("The description will be generated by social media based on page content unless you specify one.");
if (this.metaDescription.length > 160) {
- this.metaDescription = this.metaDescription.substring(0,159) + '…';
+ this.metaDescription = this.metaDescription.substring(0, 159) + '…';
}
},
@@ -731,19 +731,25 @@ var SeoConfigurator = Dialog.extend({
});
},
getMainObject: function () {
- var repr = $('html').data('main-object');
- var m = repr.match(/(.+)\((\d+),(.*)\)/);
- if (!m) {
- return null;
- } else {
- return {
- model: m[1],
- id: m[2]|0
- };
- }
+ var mainObject;
+ this.trigger_up('main_object_request', {
+ callback: function (value) {
+ mainObject = value;
+ },
+ });
+ return mainObject;
+ },
+ getSeoObject: function () {
+ var seoObject;
+ this.trigger_up('seo_object_request', {
+ callback: function (value) {
+ seoObject = value;
+ },
+ });
+ return seoObject;
},
loadMetaData: function () {
- var obj = this.getMainObject();
+ var obj = this.getSeoObject() || this.getMainObject();
return new Promise(function (resolve, reject) {
if (!obj) {
// return Promise.reject(new Error("No main_object was found."));
@@ -751,7 +757,7 @@ var SeoConfigurator = Dialog.extend({
} else {
var fields = ['website_meta_title', 'website_meta_description', 'website_meta_keywords'
,'website_meta_og_img'];
- if (obj.model === 'website.page'){
+ if (obj.model === 'website.page') {
fields.push('website_indexed');
fields.push('website_id');
}
@@ -772,7 +778,7 @@ var SeoConfigurator = Dialog.extend({
});
},
saveMetaData: function (data) {
- var obj = this.getMainObject();
+ var obj = this.getSeoObject() || this.getMainObject();
if (!obj) {
return Promise.reject();
} else {
diff --git a/addons/website/static/tests/tours/rte.js b/addons/website/static/tests/tours/rte.js
index e29f40e45ed..716562389e7 100644
--- a/addons/website/static/tests/tours/rte.js
+++ b/addons/website/static/tests/tours/rte.js
@@ -13,6 +13,7 @@ var ready = Promise.all([domReady, session.is_bound, ajax.loadXML()]);
tour.register('rte_translator', {
test: true,
+ url: '/',
wait_for: ready,
url: '/',
}, [{
diff --git a/addons/website/tests/test_get_current_website.py b/addons/website/tests/test_get_current_website.py
index a71126cb484..57d85887b4d 100644
--- a/addons/website/tests/test_get_current_website.py
+++ b/addons/website/tests/test_get_current_website.py
@@ -112,3 +112,10 @@ class TestGetCurrentWebsite(TransactionCase):
self.assertEqual(Website._get_current_website_id('site-1.com:81', False), website2.id)
self.assertEqual(Website._get_current_website_id('site-1.com:82', False), website1.id)
self.assertEqual(Website._get_current_website_id('site-1.com', False), website1.id)
+
+ def test_02_signup_user_website_id(self):
+ website = self.env['website'].browse(1)
+ website.specific_user_account = True
+
+ user = self.env['res.users'].create({'website_id': website.id, 'login': 'sad@mail.com', 'name': 'Hope Fully'})
+ self.assertTrue(user.website_id == user.partner_id.website_id == website)
diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml
index 583e019e20e..4dd19528c0d 100644
--- a/addons/website/views/website_templates.xml
+++ b/addons/website/views/website_templates.xml
@@ -169,7 +169,8 @@
'data-view-xmlid': xmlid if editable or translatable else None,
'data-viewid': viewid if editable or translatable else None,
'data-main-object': repr(main_object) if editable or translatable else None,
- 'data-oe-company-name': res_company.name
+ 'data-seo-object': repr(seo_object) if seo_object else None,
+ 'data-oe-company-name': res_company.name,
}"/>
</xpath>
<xpath expr="//head" position="before">
@@ -178,8 +179,9 @@
<t t-set="additional_title" t-value="main_object.name"/>
</t>
<t t-set="default_title"> <t t-if="additional_title"><t t-raw="additional_title"/> | </t><t t-raw="(website or res_company).name"/> </t>
- <t t-if="main_object and 'website_meta_title' in main_object and main_object.website_meta_title">
- <t t-set="title" t-value="main_object.website_meta_title"/>
+ <t t-set="seo_object" t-value="seo_object or main_object"/>
+ <t t-if="seo_object and 'website_meta_title' in seo_object and seo_object.website_meta_title">
+ <t t-set="title" t-value="seo_object.website_meta_title"/>
</t>
<t t-else="">
<t t-set="title" t-value="default_title"></t>
@@ -189,17 +191,18 @@
</xpath>
<xpath expr="//head/meta[last()]" position="after">
<meta name="generator" content="Odoo"/>
- <t t-set="website_meta" t-value="main_object and main_object.get_website_meta() or {}"/>
+ <t t-set="website_meta" t-value="seo_object and seo_object.get_website_meta() or {}"/>
<meta name="default_title" t-att-content="default_title" groups="website.group_website_designer"/>
<meta t-if="main_object and 'website_indexed' in main_object
and not main_object.website_indexed" name="robots" content="noindex"/>
- <t t-set="meta_description" t-value="main_object and 'website_meta_description' in main_object
- and main_object.website_meta_description or website_meta_description or website_meta.get('meta_description', '')"/>
- <t t-set="meta_keywords" t-value="main_object and 'website_meta_keywords' in main_object
- and main_object.website_meta_keywords or website_meta_keywords"/>
+ <t t-set="seo_object" t-value="seo_object or main_object"/>
+ <t t-set="meta_description" t-value="seo_object and 'website_meta_description' in seo_object
+ and seo_object.website_meta_description or website_meta_description or website_meta.get('meta_description', '')"/>
+ <t t-set="meta_keywords" t-value="seo_object and 'website_meta_keywords' in seo_object
+ and seo_object.website_meta_keywords or website_meta_keywords"/>
<meta t-if="meta_description or editable" name="description" t-att-content="meta_description"/>
<meta t-if="meta_keywords or editable" name="keywords" t-att-content="meta_keywords"/>
- <t t-if="main_object">
+ <t t-if="seo_object">
<meta name="default_description" t-att-content="website_meta_description or website_meta.get('meta_description')" groups="website.group_website_designer"/>
<!-- OpenGraph tags for Facebook sharing -->
<t t-set="opengraph_meta" t-value="website_meta.get('opengraph_meta')"/>
@@ -399,7 +402,7 @@
</div>
</li>
<li groups="website.group_website_publisher" class="list-inline-item">
- <t t-set="url_return" t-value="url_for('', '[lang]') + '?' + keep_query()"/>
+ <t t-set="url_return" t-value="quote_plus(url_for('', '[lang]') + '?' + keep_query())"/>
<a class="d-none d-sm-block" t-attf-href="/web#action=base.action_view_base_language_install&amp;website_id=#{website.id if website else ''}&amp;url_return=#{url_return}">
<i class="fa fa-plus-circle"/>
Add a language...