[IMP] base, web, website, *: differentiate essential & optional cookies
*: im_livechat, survey, utm, website_crm_iap_reveal, website_forum, website_livechat, website_sale, website_sale_comparison Before this commit all cookies were considered essential. This commit makes some of them optional. It also makes it possible for the website visitor to only accept the essential cookies. task-2800976 X-original-commit: 9a8a9463289a7446e9be0ef62ff895feb37a4de4 Part-of: odoo/odoo#101845 Co-authored-by: Benoit Socias <bso@odoo.com>
This commit is contained in:
committed by
Benoit Socias
co-authored by
Benoit Socias
parent
6a9b612a1d
commit
878351d840
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import time from 'web.time';
|
||||
import utils from 'web.utils';
|
||||
import {getCookie} from 'web.utils.cookies';
|
||||
import Widget from 'web.Widget';
|
||||
|
||||
const LivechatButton = Widget.extend({
|
||||
@@ -33,7 +33,7 @@ const LivechatButton = Widget.extend({
|
||||
* @return {integer} operator_id.partner_id.id if the cookie is set
|
||||
*/
|
||||
_get_previous_operator_id() {
|
||||
const cookie = utils.get_cookie('im_livechat_previous_operator_pid');
|
||||
const cookie = getCookie('im_livechat_previous_operator_pid');
|
||||
if (cookie) {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
+3
-2
@@ -4,7 +4,8 @@ import config from 'web.config';
|
||||
import { _t, qweb } from 'web.core';
|
||||
import Widget from 'web.Widget';
|
||||
|
||||
import { set_cookie, unaccent } from 'web.utils';
|
||||
import {unaccent} from 'web.utils';
|
||||
import {setCookie} from 'web.utils.cookies';
|
||||
|
||||
/**
|
||||
* This is the widget that represent windows of livechat in the frontend.
|
||||
@@ -137,7 +138,7 @@ const PublicLivechatWindow = Widget.extend({
|
||||
folded = !this.messaging.publicLivechatGlobal.publicLivechat.isFolded;
|
||||
}
|
||||
this.messaging.publicLivechatGlobal.publicLivechat.update({ isFolded: folded });
|
||||
set_cookie('im_livechat_session', unaccent(JSON.stringify(this.messaging.publicLivechatGlobal.publicLivechat.widget.toData()), true), 60 * 60);
|
||||
setCookie('im_livechat_session', unaccent(JSON.stringify(this.messaging.publicLivechatGlobal.publicLivechat.widget.toData()), true), 60 * 60, 'required');
|
||||
this.updateVisualFoldState();
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,8 @@ import { registerModel } from '@mail/model/model_core';
|
||||
import { attr, one } from '@mail/model/model_field';
|
||||
import { clear } from '@mail/model/model_field_command';
|
||||
|
||||
import { get_cookie, set_cookie, unaccent } from 'web.utils';
|
||||
import {unaccent} from 'web.utils';
|
||||
import {getCookie, setCookie, deleteCookie} from 'web.utils.cookies';
|
||||
|
||||
registerModel({
|
||||
name: 'LivechatButtonView',
|
||||
@@ -106,18 +107,18 @@ registerModel({
|
||||
},
|
||||
closeChat() {
|
||||
this.messaging.publicLivechatGlobal.update({ chatWindow: clear() });
|
||||
set_cookie('im_livechat_session', "", -1); // remove cookie
|
||||
deleteCookie('im_livechat_session');
|
||||
},
|
||||
/**
|
||||
* Called when the visitor leaves the livechat chatter the first time (first click on X button)
|
||||
* this will deactivate the mail_channel, notify operator that visitor has left the channel.
|
||||
*/
|
||||
leaveSession() {
|
||||
const cookie = get_cookie('im_livechat_session');
|
||||
const cookie = getCookie('im_livechat_session');
|
||||
if (cookie) {
|
||||
const channel = JSON.parse(cookie);
|
||||
this.messaging.rpc({ route: '/im_livechat/visitor_leave_session', params: { uuid: channel.uuid } });
|
||||
set_cookie('im_livechat_session', "", -1); // remove cookie
|
||||
deleteCookie('im_livechat_session');
|
||||
}
|
||||
},
|
||||
openChat() {
|
||||
@@ -152,7 +153,7 @@ registerModel({
|
||||
}
|
||||
this.openChat();
|
||||
} else if (!this.messaging.device.isSmall && this.messaging.publicLivechatGlobal.rule.action === 'auto_popup') {
|
||||
const autoPopupCookie = get_cookie('im_livechat_auto_popup');
|
||||
const autoPopupCookie = getCookie('im_livechat_auto_popup');
|
||||
if (!autoPopupCookie || JSON.parse(autoPopupCookie)) {
|
||||
this.update({
|
||||
autoOpenChatTimeout: setTimeout(
|
||||
@@ -182,7 +183,7 @@ registerModel({
|
||||
if (this.isOpeningChat) {
|
||||
return;
|
||||
}
|
||||
const cookie = get_cookie('im_livechat_session');
|
||||
const cookie = getCookie('im_livechat_session');
|
||||
let def;
|
||||
this.update({ isOpeningChat: true });
|
||||
clearTimeout(this.autoOpenChatTimeout);
|
||||
@@ -224,12 +225,12 @@ registerModel({
|
||||
this.messaging.publicLivechatGlobal.chatWindow.renderMessages();
|
||||
this.messaging.publicLivechatGlobal.update({ notificationHandler: {} });
|
||||
|
||||
set_cookie('im_livechat_session', unaccent(JSON.stringify(this.messaging.publicLivechatGlobal.publicLivechat.widget.toData()), true), 60 * 60);
|
||||
set_cookie('im_livechat_auto_popup', JSON.stringify(false), 60 * 60);
|
||||
setCookie('im_livechat_session', unaccent(JSON.stringify(this.messaging.publicLivechatGlobal.publicLivechat.widget.toData()), true), 60 * 60, 'required');
|
||||
setCookie('im_livechat_auto_popup', JSON.stringify(false), 60 * 60, 'optional');
|
||||
if (this.messaging.publicLivechatGlobal.publicLivechat.operator) {
|
||||
const operatorPidId = this.messaging.publicLivechatGlobal.publicLivechat.operator.id;
|
||||
const oneWeek = 7 * 24 * 60 * 60;
|
||||
set_cookie('im_livechat_previous_operator_pid', operatorPidId, oneWeek);
|
||||
setCookie('im_livechat_previous_operator_pid', operatorPidId, oneWeek, 'optional');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import { attr, many, one } from '@mail/model/model_field';
|
||||
import { clear } from '@mail/model/model_field_command';
|
||||
|
||||
import { qweb } from 'web.core';
|
||||
|
||||
import { get_cookie, Markup, set_cookie } from 'web.utils';
|
||||
import { Markup } from 'web.utils';
|
||||
import {getCookie, setCookie, deleteCookie} from 'web.utils.cookies';
|
||||
|
||||
registerModel({
|
||||
name: 'PublicLivechatGlobal',
|
||||
@@ -14,7 +14,7 @@ registerModel({
|
||||
_created() {
|
||||
// History tracking
|
||||
const page = window.location.href.replace(/^.*\/\/[^/]+/, '');
|
||||
const pageHistory = get_cookie(this.LIVECHAT_COOKIE_HISTORY);
|
||||
const pageHistory = getCookie(this.LIVECHAT_COOKIE_HISTORY);
|
||||
let urlHistory = [];
|
||||
if (pageHistory) {
|
||||
urlHistory = JSON.parse(pageHistory) || [];
|
||||
@@ -24,7 +24,7 @@ registerModel({
|
||||
while (urlHistory.length > this.HISTORY_LIMIT) {
|
||||
urlHistory.shift();
|
||||
}
|
||||
set_cookie(this.LIVECHAT_COOKIE_HISTORY, JSON.stringify(urlHistory), 60 * 60 * 24); // 1 day cookie
|
||||
setCookie(this.LIVECHAT_COOKIE_HISTORY, JSON.stringify(urlHistory), 60 * 60 * 24, 'optional'); // 1 day cookie
|
||||
}
|
||||
if (this.isAvailable) {
|
||||
this.willStart();
|
||||
@@ -44,7 +44,7 @@ registerModel({
|
||||
await this._willStartChatbot();
|
||||
},
|
||||
async _willStart() {
|
||||
const cookie = get_cookie('im_livechat_session');
|
||||
const cookie = getCookie('im_livechat_session');
|
||||
if (cookie) {
|
||||
const channel = JSON.parse(cookie);
|
||||
const history = await this.messaging.rpc({
|
||||
@@ -98,7 +98,7 @@ registerModel({
|
||||
}),
|
||||
});
|
||||
} else if (this.history !== null && this.history.length !== 0) {
|
||||
const sessionCookie = get_cookie('im_livechat_session');
|
||||
const sessionCookie = getCookie('im_livechat_session');
|
||||
if (sessionCookie) {
|
||||
this.update({ sessionCookie });
|
||||
}
|
||||
@@ -120,7 +120,7 @@ registerModel({
|
||||
// -> remove cookie to force opening the popup again
|
||||
// -> initialize necessary state
|
||||
// -> batch welcome message (see '_sendWelcomeChatbotMessage')
|
||||
set_cookie('im_livechat_auto_popup', '', -1);
|
||||
deleteCookie('im_livechat_auto_popup');
|
||||
this.update({ history: clear() });
|
||||
this.update({ rule: this.livechatInit.rule });
|
||||
} else if (this.chatbot.state === 'restore_session') {
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@ import { increment } from '@mail/model/model_field_command';
|
||||
|
||||
import session from 'web.session';
|
||||
import utils from 'web.utils';
|
||||
import {getCookie} from 'web.utils.cookies';
|
||||
|
||||
registerModel({
|
||||
name: 'PublicLivechatGlobalNotificationHandler',
|
||||
@@ -28,7 +29,7 @@ registerModel({
|
||||
if (payload.id !== this.messaging.publicLivechatGlobal.publicLivechat.id) {
|
||||
return;
|
||||
}
|
||||
const cookie = utils.get_cookie(this.messaging.publicLivechatGlobal.LIVECHAT_COOKIE_HISTORY);
|
||||
const cookie = getCookie(this.messaging.publicLivechatGlobal.LIVECHAT_COOKIE_HISTORY);
|
||||
const history = cookie ? JSON.parse(cookie) : [];
|
||||
session.rpc('/im_livechat/history', {
|
||||
pid: this.messaging.publicLivechatGlobal.publicLivechat.operator.id,
|
||||
|
||||
@@ -8,7 +8,7 @@ var config = require('web.config');
|
||||
var core = require('web.core');
|
||||
var Dialog = require('web.Dialog');
|
||||
var dom = require('web.dom');
|
||||
var utils = require('web.utils');
|
||||
const {getCookie, setCookie, deleteCookie} = require('web.utils.cookies');
|
||||
|
||||
var SurveyPreloadImageMixin = require('survey.preload_image_mixin');
|
||||
const { SurveyImageZoomer } = require("@survey/js/survey_image_zoomer");
|
||||
@@ -48,8 +48,8 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend(SurveyPreloa
|
||||
self.imgZoomer = false;
|
||||
|
||||
// Add Survey cookie to retrieve the survey if you quit the page and restart the survey.
|
||||
if (!utils.get_cookie('survey_' + self.options.surveyToken)) {
|
||||
utils.set_cookie('survey_' + self.options.surveyToken, self.options.answerToken, 60*60*24);
|
||||
if (!getCookie('survey_' + self.options.surveyToken)) {
|
||||
setCookie('survey_' + self.options.surveyToken, self.options.answerToken, 60 * 60 * 24, 'optional');
|
||||
}
|
||||
|
||||
// Init fields
|
||||
@@ -502,7 +502,7 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend(SurveyPreloa
|
||||
var selectorsToFadeout = ['.o_survey_form_content'];
|
||||
if (options.isFinish) {
|
||||
selectorsToFadeout.push('.breadcrumb', '.o_survey_timer');
|
||||
utils.set_cookie('survey_' + self.options.surveyToken, '', -1); // delete cookie
|
||||
deleteCookie('survey_' + self.options.surveyToken);
|
||||
}
|
||||
self.$(selectorsToFadeout.join(',')).fadeOut(this.fadeInOutDelay, function () {
|
||||
resolveFadeOut();
|
||||
|
||||
@@ -16,7 +16,7 @@ class IrHttp(models.AbstractModel):
|
||||
domain = cls.get_utm_domain_cookies()
|
||||
for url_parameter, __, cookie_name in request.env['utm.mixin'].tracking_fields():
|
||||
if url_parameter in request.params and request.httprequest.cookies.get(cookie_name) != request.params[url_parameter]:
|
||||
response.set_cookie(cookie_name, request.params[url_parameter], domain=domain)
|
||||
response.set_cookie(cookie_name, request.params[url_parameter], domain=domain, cookie_type='optional')
|
||||
|
||||
@classmethod
|
||||
def _post_dispatch(cls, response):
|
||||
|
||||
@@ -36,6 +36,8 @@ function makeCookieService() {
|
||||
}
|
||||
let cookie = getCurrent();
|
||||
function setCookie(key, value, ttl) {
|
||||
// TODO When this will be used from website pages, recover the
|
||||
// optional cookie mechanism.
|
||||
document.cookie = cookieToString(key, value, ttl);
|
||||
cookie = getCurrent();
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ odoo.define("web.commonEnv", function (require) {
|
||||
const rpc = require("web.rpc");
|
||||
const session = require("web.session");
|
||||
const { _t } = require("web.translation");
|
||||
const utils = require("web.utils");
|
||||
const {getCookie, setCookie} = require('web.utils.cookies');
|
||||
|
||||
const browser = {
|
||||
clearInterval: window.clearInterval.bind(window),
|
||||
@@ -54,7 +54,7 @@ odoo.define("web.commonEnv", function (require) {
|
||||
return jsonRpc(...arguments);
|
||||
},
|
||||
getCookie() {
|
||||
return utils.get_cookie(...arguments);
|
||||
return getCookie(...arguments);
|
||||
},
|
||||
httpRequest(route, params = {}, readMethod = 'json') {
|
||||
const info = {
|
||||
@@ -90,7 +90,7 @@ odoo.define("web.commonEnv", function (require) {
|
||||
return session.rpc(query.route, query.params, options);
|
||||
},
|
||||
setCookie() {
|
||||
utils.set_cookie(...arguments);
|
||||
setCookie(...arguments);
|
||||
},
|
||||
},
|
||||
session,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
odoo.define('web.utils.cookies', function (require) {
|
||||
"use strict";
|
||||
|
||||
return {
|
||||
const utils = {
|
||||
/**
|
||||
* Reads the cookie described by the given name.
|
||||
*
|
||||
* @param {string} cookieName
|
||||
* @returns {string}
|
||||
*/
|
||||
get_cookie(cookieName) {
|
||||
getCookie(cookieName) {
|
||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||
for (var i = 0, l = cookies.length; i < l; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
@@ -21,21 +21,47 @@ return {
|
||||
}
|
||||
return "";
|
||||
},
|
||||
/**
|
||||
* Check if cookie can be written.
|
||||
*
|
||||
* @param {String} type the type of the cookie
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isAllowedCookie(type) {
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* Creates a cookie.
|
||||
*
|
||||
* @param {string} name the name of the cookie
|
||||
* @param {string} value the value stored in the cookie
|
||||
* @param {integer} ttl time to live of the cookie in millis. -1 to erase the cookie.
|
||||
* @param {string} type the type of the cookies ('required' as default value)
|
||||
*/
|
||||
set_cookie(name, value, ttl) {
|
||||
setCookie(name, value, ttl = 31536000, type = 'required') {
|
||||
ttl = ttl || 24 * 60 * 60 * 365;
|
||||
if (utils.isAllowedCookie(type)) {
|
||||
document.cookie = [
|
||||
`${name}=${value}`,
|
||||
'path=/',
|
||||
`max-age=${ttl}`,
|
||||
`expires=${new Date(new Date().getTime() + ttl * 1000).toGMTString()}`,
|
||||
].join(';');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Deletes a cookie.
|
||||
*
|
||||
* @param {string} name the name of the cookie
|
||||
*/
|
||||
deleteCookie(name) {
|
||||
document.cookie = [
|
||||
`${name}=${value}`,
|
||||
`${name}=`,
|
||||
'path=/',
|
||||
`max-age=${ttl}`,
|
||||
`expires=${new Date(new Date().getTime() + ttl * 1000).toGMTString()}`
|
||||
`max-age=-1`,
|
||||
`expires=${new Date(new Date().getTime() - 1000).toGMTString()}`,
|
||||
].join(';');
|
||||
},
|
||||
};
|
||||
return utils;
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ odoo.define('web.Session', function (require) {
|
||||
var ajax = require('web.ajax');
|
||||
var core = require('web.core');
|
||||
var mixins = require('web.mixins');
|
||||
var utils = require('web.utils');
|
||||
const {setCookie} = require('web.utils.cookies');
|
||||
const { session } = require('@web/session');
|
||||
const { loadJS } = require('@web/core/assets');
|
||||
|
||||
@@ -172,11 +172,12 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
* @param name the cookie's name
|
||||
* @param value the cookie's value
|
||||
* @param ttl the cookie's time to live, 1 year by default, set to -1 to delete
|
||||
* @param type the type of the cookies ('required' as default value)
|
||||
*/
|
||||
set_cookie: function (name, value, ttl) {
|
||||
set_cookie(name, value, ttl, type = 'required') {
|
||||
if (!this.name) { return; }
|
||||
ttl = ttl || 24*60*60*365;
|
||||
utils.set_cookie(this.name + '|' + name, value, ttl);
|
||||
setCookie(this.name + '|' + name, value, ttl, type);
|
||||
},
|
||||
/**
|
||||
* Load additional web addons of that instance and init them
|
||||
@@ -328,7 +329,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
return a - b;
|
||||
}
|
||||
}).join(',');
|
||||
utils.set_cookie('cids', hash.cids || String(main_company_id));
|
||||
setCookie('cids', hash.cids || String(main_company_id), 24 * 60 * 60 * 365, 'required');
|
||||
$.bbq.pushState({'cids': hash.cids}, 0);
|
||||
location.reload();
|
||||
},
|
||||
|
||||
@@ -8,7 +8,6 @@ odoo.define('web.utils', function (require) {
|
||||
*/
|
||||
|
||||
var translation = require('web.translation');
|
||||
var cookieUtils = require('web.utils.cookies');
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
@@ -316,7 +315,7 @@ function Markup(v, ...exprs) {
|
||||
return new _Markup(s);
|
||||
}
|
||||
|
||||
var utils = Object.assign({
|
||||
const utils = {
|
||||
AlreadyDefinedPatchError,
|
||||
UnknownPatchError,
|
||||
Markup,
|
||||
@@ -1129,7 +1128,7 @@ var utils = Object.assign({
|
||||
}
|
||||
return curr;
|
||||
},
|
||||
}, cookieUtils);
|
||||
};
|
||||
|
||||
return utils;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import dom from 'web.dom';
|
||||
import legacyEnv from 'web.public_env';
|
||||
import session from 'web.session';
|
||||
import utils from 'web.utils';
|
||||
import {getCookie} from 'web.utils.cookies';
|
||||
import publicWidget from 'web.public.widget';
|
||||
import { registry } from '@web/core/registry';
|
||||
|
||||
@@ -37,7 +37,7 @@ function getLang() {
|
||||
var html = document.documentElement;
|
||||
return (html.getAttribute('lang') || 'en_US').replace('-', '_');
|
||||
}
|
||||
var lang = utils.get_cookie('frontend_lang') || getLang(); // FIXME the cookie value should maybe be in the ctx?
|
||||
const lang = getCookie('frontend_lang') || getLang(); // FIXME the cookie value should maybe be in the ctx?
|
||||
// momentjs don't have config for en_US, so avoid useless RPC
|
||||
var localeDef = lang !== 'en_US' ? loadJS('/web/webclient/locale/' + lang.replace('-', '_')) : Promise.resolve();
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
'website/static/src/js/post_link.js',
|
||||
'website/static/src/js/plausible.js',
|
||||
'website/static/src/js/user_custom_javascript.js',
|
||||
'website/static/src/js/http_cookie.js',
|
||||
'website/static/src/xml/website.xml',
|
||||
'website/static/src/xml/website.background.video.xml',
|
||||
'website/static/src/xml/website.share.xml',
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p>Session & Security</p>
|
||||
<p>Session & Security<br/>(essential)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
@@ -243,7 +243,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p>Preferences</p>
|
||||
<p>Preferences<br/>(essential)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Remember information about the preferred look or behavior of the website, such as your preferred language or region.</p>
|
||||
@@ -254,7 +254,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Interaction History</td>
|
||||
<td>Interaction History<br/>(optional)</td>
|
||||
<td>
|
||||
<p>
|
||||
Used to collect information about your interactions with the website, the pages you've seen,
|
||||
@@ -271,7 +271,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p>Advertising & Marketing</p>
|
||||
<p>Advertising & Marketing<br/>(optional)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
@@ -291,7 +291,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p>Analytics</p>
|
||||
<p>Analytics<br/>(optional)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>
|
||||
|
||||
@@ -17,6 +17,7 @@ from odoo import api, models
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.http import request
|
||||
from odoo.tools.json import scriptsafe as json_scriptsafe
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from odoo.osv.expression import FALSE_DOMAIN
|
||||
from odoo.addons.http_routing.models import ir_http
|
||||
@@ -380,6 +381,22 @@ class Http(models.AbstractModel):
|
||||
session_info['bundle_params']['website_id'] = request.website.id
|
||||
return session_info
|
||||
|
||||
@classmethod
|
||||
def _is_allowed_cookie(cls, cookie_type):
|
||||
result = super()._is_allowed_cookie(cookie_type)
|
||||
if result and cookie_type == 'optional':
|
||||
if not request.env['website'].get_current_website().cookies_bar:
|
||||
# Cookies bar is disabled on this website
|
||||
return True
|
||||
accepted_cookie_types = json_scriptsafe.loads(request.httprequest.cookies.get('website_cookies_bar', '{}'))
|
||||
if 'optional' in accepted_cookie_types:
|
||||
return accepted_cookie_types['optional']
|
||||
return False
|
||||
|
||||
# Pass-through if already forbidden for another reason or a type that
|
||||
# is not restricted by the website module.
|
||||
return result
|
||||
|
||||
|
||||
class ModelConverter(ir_http.ModelConverter):
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { get_cookie } from 'web.utils.cookies';
|
||||
import {getCookie} from 'web.utils.cookies';
|
||||
import { session } from '@web/session';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
@@ -13,7 +13,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
'utm_campaign': 'utmCampaign',
|
||||
};
|
||||
for (const [name, dsName] of Object.entries(cookieNamesToDataNames)) {
|
||||
const cookie = get_cookie(`odoo_${name}`);
|
||||
const cookie = getCookie(`odoo_${name}`);
|
||||
if (cookie) {
|
||||
// Remove leading and trailing " and '
|
||||
htmlEl.dataset[dsName] = cookie.replace(/(^["']|["']$)/g, '');
|
||||
|
||||
@@ -2617,6 +2617,7 @@ options.registry.CookiesBar = options.registry.SnippetPopup.extend({
|
||||
const $content = this.$target.find('.modal-content');
|
||||
const selectorsToKeep = [
|
||||
'.o_cookies_bar_text_button',
|
||||
'.o_cookies_bar_text_button_essential',
|
||||
'.o_cookies_bar_text_policy',
|
||||
'.o_cookies_bar_text_title',
|
||||
'.o_cookies_bar_text_primary',
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import cookieUtils from 'web.utils.cookies';
|
||||
|
||||
const originFunc = cookieUtils.isAllowedCookie;
|
||||
cookieUtils.isAllowedCookie = (type) => {
|
||||
const result = originFunc.apply(cookieUtils, [type]);
|
||||
if (result && type === 'optional') {
|
||||
if (!document.getElementById('cookies-consent-essential')) {
|
||||
// Cookies bar is disabled on this website.
|
||||
return true;
|
||||
}
|
||||
const consents = JSON.parse(cookieUtils.getCookie('website_cookies_bar') || '{}');
|
||||
if ('optional' in consents) {
|
||||
return consents['optional'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Pass-through if already forbidden for another reason or a type that is
|
||||
// not restricted by the website module.
|
||||
return result;
|
||||
};
|
||||
@@ -1487,17 +1487,6 @@ $ribbon-padding: 100px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
// Cookies Bar
|
||||
#website_cookies_bar {
|
||||
.o_cookies_discrete {
|
||||
.js_close_popup.o_cookies_bar_text_button, .o_cookies_bar_text_policy {
|
||||
@include media-breakpoint-down(lg) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_website_btn_loading {
|
||||
cursor: wait;
|
||||
opacity: $btn-disabled-opacity;
|
||||
|
||||
@@ -3,7 +3,7 @@ odoo.define('website.s_popup', function (require) {
|
||||
|
||||
const config = require('web.config');
|
||||
const publicWidget = require('web.public.widget');
|
||||
const utils = require('web.utils');
|
||||
const {getCookie, setCookie} = require('web.utils.cookies');
|
||||
|
||||
const PopupWidget = publicWidget.Widget.extend({
|
||||
selector: '.s_popup',
|
||||
@@ -12,12 +12,13 @@ const PopupWidget = publicWidget.Widget.extend({
|
||||
'hide.bs.modal': '_onHideModal',
|
||||
'show.bs.modal': '_onShowModal',
|
||||
},
|
||||
cookieValue: true,
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this._popupAlreadyShown = !!utils.get_cookie(this.$el.attr('id'));
|
||||
this._popupAlreadyShown = !!getCookie(this.$el.attr('id'));
|
||||
if (!this._popupAlreadyShown) {
|
||||
this._bindPopup();
|
||||
}
|
||||
@@ -96,7 +97,7 @@ const PopupWidget = publicWidget.Widget.extend({
|
||||
*/
|
||||
_onHideModal: function () {
|
||||
const nbDays = this.$el.find('.modal').data('consentsDuration');
|
||||
utils.set_cookie(this.$el.attr('id'), true, nbDays * 24 * 60 * 60);
|
||||
setCookie(this.el.id, this.cookieValue, nbDays * 24 * 60 * 60, 'required');
|
||||
this._popupAlreadyShown = true;
|
||||
|
||||
this.$target.find('.media_iframe_video iframe').each((i, iframe) => {
|
||||
@@ -116,5 +117,28 @@ const PopupWidget = publicWidget.Widget.extend({
|
||||
|
||||
publicWidget.registry.popup = PopupWidget;
|
||||
|
||||
// Extending the popup widget with cookiebar functionality.
|
||||
// This allows for refusing optional cookies for now and can be
|
||||
// extended to picking which cookies categories are accepted.
|
||||
publicWidget.registry.cookies_bar = PopupWidget.extend({
|
||||
selector: '#website_cookies_bar',
|
||||
events: Object.assign({}, PopupWidget.prototype.events, {
|
||||
'click #cookies-consent-essential, #cookies-consent-all': '_onAcceptClick',
|
||||
}),
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param ev
|
||||
*/
|
||||
_onAcceptClick(ev) {
|
||||
this.cookieValue = `{"required": true, "optional": ${ev.target.id === 'cookies-consent-all'}}`;
|
||||
this._onHideModal();
|
||||
},
|
||||
});
|
||||
|
||||
return PopupWidget;
|
||||
});
|
||||
|
||||
@@ -7,25 +7,37 @@
|
||||
</t>
|
||||
<t t-name="website.cookies_bar.text_primary">
|
||||
<p class="o_cookies_bar_text_primary">
|
||||
We use cookies to provide you a better user experience.
|
||||
Allow the use of cookies from this website on this browser?
|
||||
</p>
|
||||
</t>
|
||||
<t t-name="website.cookies_bar.text_secondary">
|
||||
<p class="o_cookies_bar_text_secondary">
|
||||
We use them to store info about your habits on our website. It will helps us to provide you the very best experience and customize what you see. <br/>
|
||||
By clicking on this banner, you give us permission to collect data.
|
||||
We use cookies to provide improved experience on this website. You can learn more about our cookies and how we use them in our <a href="/cookie-policy" class="o_cookies_bar_text_policy">Cookie Policy</a>.
|
||||
</p>
|
||||
</t>
|
||||
<t t-name="website.cookies_bar.text_button_all">
|
||||
<a href="#" id="cookies-consent-all" role="button"
|
||||
class="js_close_popup o_cookies_bar_accept_all o_cookies_bar_text_button btn btn-primary mb-1 px-2 py-1">Allow all cookies</a>
|
||||
</t>
|
||||
<t t-name="website.cookies_bar.text_button_essential">
|
||||
<a href="#" id="cookies-consent-essential" role="button"
|
||||
class="js_close_popup o_cookies_bar_accept_essential o_cookies_bar_text_button_essential btn btn-link mt-1 mb-2 px-2 py-1">Only allow essential cookies</a>
|
||||
</t>
|
||||
<t t-name="website.cookies_bar.discrete">
|
||||
<!-- When updating this template, do not forget to also update the
|
||||
backend `website.cookies_bar` template -->
|
||||
<section class="o_colored_level o_cc o_cc1">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 pt16">
|
||||
<p>We use cookies to provide you a better user experience.</p>
|
||||
<div class="row pt16 pb16">
|
||||
<div class="col-lg-8">
|
||||
<span class="pe-1">We use cookies to provide you a better user experience on this website.</span>
|
||||
<a href="/cookie-policy" class="o_cookies_bar_text_policy btn btn-link btn-sm px-0">Cookie Policy</a>
|
||||
</div>
|
||||
<div class="col-lg-4 pt16 text-end">
|
||||
<a href="/cookie-policy" class="o_cookies_bar_text_policy btn btn-link btn-sm">Cookie Policy</a>
|
||||
<a href="#" role="button" class="js_close_popup o_cookies_bar_text_button btn btn-primary btn-sm">I agree</a>
|
||||
<div class="col-lg-4 text-end">
|
||||
<a href="#" id="cookies-consent-essential" role="button"
|
||||
class="js_close_popup btn btn-link btn-sm px-2">Only essentials</a>
|
||||
<a href="#" id="cookies-consent-all" role="button"
|
||||
class="js_close_popup btn btn-primary btn-sm">I agree</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,9 +52,15 @@
|
||||
<t t-call="website.cookies_bar.text_primary"/>
|
||||
<t t-call="website.cookies_bar.text_secondary"/>
|
||||
</div>
|
||||
<div class="col-lg-3 offset-lg-3">
|
||||
<a href="#" role="button" class="js_close_popup o_cookies_bar_text_button btn btn-primary btn-block">I agree</a>
|
||||
<a href="/cookie-policy" class="o_cookies_bar_text_policy btn btn-link btn-block">Cookie Policy</a>
|
||||
<div class="col-lg-3 d-flex align-items-center">
|
||||
<div class="row">
|
||||
<div class="col-lg-12 d-flex align-items-center">
|
||||
<t t-call="website.cookies_bar.text_button_all"/>
|
||||
</div>
|
||||
<div class="col-lg-12 d-flex align-items-center">
|
||||
<t t-call="website.cookies_bar.text_button_essential"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,8 +75,8 @@
|
||||
<t t-call="website.cookies_bar.text_title"/>
|
||||
<t t-call="website.cookies_bar.text_primary"/>
|
||||
<t t-call="website.cookies_bar.text_secondary"/>
|
||||
<a href="/cookie-policy" class=" o_cookies_bar_text_policy btn btn-link me-2">Cookie Policy</a>
|
||||
<a href="#" role="button" class="js_close_popup o_cookies_bar_text_button btn btn-primary">I agree</a>
|
||||
<t t-call="website.cookies_bar.text_button_all"/>
|
||||
<t t-call="website.cookies_bar.text_button_essential"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//div[@id='wrapwrap']" position="after">
|
||||
<t t-if="website and website.google_analytics_key and not editable">
|
||||
<t t-if="website and website.google_analytics_key and request.env['ir.http']._is_allowed_cookie('optional') and not editable">
|
||||
<script id="tracking_code" async="1" t-attf-src="https://www.googletagmanager.com/gtag/js?id={{ website.google_analytics_key }}"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
@@ -1894,15 +1894,19 @@
|
||||
role="dialog">
|
||||
<div class="modal-dialog d-flex s_popup_size_full">
|
||||
<div class="modal-content oe_structure">
|
||||
<!-- Keep this section equivalent to the rendering of the `website.cookies_bar.discrete` client template -->
|
||||
<section class="o_colored_level o_cc o_cc1">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 pt16">
|
||||
<p>We use cookies to provide you a better user experience.</p>
|
||||
<div class="row pt16 pb16">
|
||||
<div class="col-lg-8">
|
||||
<span class="pe-1">We use cookies to provide you a better user experience on this website.</span>
|
||||
<a href="/cookie-policy" class="o_cookies_bar_text_policy btn btn-link btn-sm px-0">Cookie Policy</a>
|
||||
</div>
|
||||
<div class="col-lg-4 pt16 text-end">
|
||||
<a href="/cookie-policy" class="o_cookies_bar_text_policy btn btn-link btn-sm">Cookie Policy</a>
|
||||
<a href="#" role="button" class="js_close_popup o_cookies_bar_text_button btn btn-primary btn-sm">I agree</a>
|
||||
<div class="col-lg-4 text-end">
|
||||
<a href="#" id="cookies-consent-essential" role="button"
|
||||
class="js_close_popup btn btn-link btn-sm px-2">Only essentials</a>
|
||||
<a href="#" id="cookies-consent-all" role="button"
|
||||
class="js_close_popup btn btn-primary btn-sm">I agree</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -37,7 +37,7 @@ class IrHttp(models.AbstractModel):
|
||||
time.time() - before, new_rules_excluded == rules_excluded, country_code,
|
||||
ip_address)
|
||||
if new_rules_excluded:
|
||||
response.set_cookie('rule_ids', ','.join(new_rules_excluded))
|
||||
response.set_cookie('rule_ids', ','.join(new_rules_excluded), cookie_type='optional')
|
||||
except Exception:
|
||||
# just in case - we never want to crash a page view
|
||||
_logger.exception("Failed to process reveal rules")
|
||||
|
||||
@@ -3,6 +3,7 @@ odoo.define('website_forum.website_forum', function (require) {
|
||||
|
||||
const dom = require('web.dom');
|
||||
var core = require('web.core');
|
||||
const {setCookie} = require('web.utils.cookies');
|
||||
var Dialog = require('web.Dialog');
|
||||
var wysiwygLoader = require('web_editor.loader');
|
||||
var publicWidget = require('web.public.widget');
|
||||
@@ -497,7 +498,7 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
|
||||
*/
|
||||
_onCloseIntroClick: function (ev) {
|
||||
ev.preventDefault();
|
||||
document.cookie = 'forum_welcome_message = false';
|
||||
setCookie('forum_welcome_message', false, 24 * 60 * 60 * 365, 'optional');
|
||||
$('.forum_intro').slideUp();
|
||||
return true;
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module alias=website_livechat.chatbot_test_script **/
|
||||
|
||||
import publicWidget from 'web.public.widget';
|
||||
import utils from 'web.utils';
|
||||
import {deleteCookie} from 'web.utils.cookies';
|
||||
|
||||
import LivechatButton from '@im_livechat/legacy/widgets/livechat_button';
|
||||
|
||||
@@ -45,10 +45,10 @@ publicWidget.registry.livechatChatbotTestScript = publicWidget.Widget.extend({
|
||||
* Remove any existing session cookie to start fresh
|
||||
*/
|
||||
async start() {
|
||||
utils.set_cookie('im_livechat_session', '', -1);
|
||||
utils.set_cookie('im_livechat_auto_popup', '', -1);
|
||||
utils.set_cookie('im_livechat_history', '', -1);
|
||||
utils.set_cookie('im_livechat_previous_operator_pid', '', -1);
|
||||
deleteCookie('im_livechat_session');
|
||||
deleteCookie('im_livechat_auto_popup');
|
||||
deleteCookie('im_livechat_history');
|
||||
deleteCookie('im_livechat_previous_operator_pid');
|
||||
const messaging = await this.env.services.messaging.get();
|
||||
return this._super(...arguments).then(() => {
|
||||
messaging.update({
|
||||
|
||||
@@ -5,7 +5,8 @@ import { clear } from '@mail/model/model_field_command';
|
||||
// ensure that the model definition is loaded before the patch
|
||||
import '@im_livechat/public_models/livechat_button_view';
|
||||
|
||||
import { set_cookie, unaccent } from 'web.utils';
|
||||
import {unaccent} from 'web.utils';
|
||||
import {setCookie} from 'web.utils.cookies';
|
||||
|
||||
patchFields('LivechatButtonView', {
|
||||
isOpenChatDebounced: {
|
||||
@@ -53,7 +54,7 @@ patchRecordMethods('LivechatButtonView', {
|
||||
this.widget._sendWelcomeMessage();
|
||||
this.messaging.publicLivechatGlobal.chatWindow.renderMessages();
|
||||
this.env.services.bus_service.addChannel(this.messaging.publicLivechatGlobal.publicLivechat.uuid);
|
||||
set_cookie('im_livechat_session', unaccent(JSON.stringify(this.messaging.publicLivechatGlobal.publicLivechat.widget.toData()), true), 60 * 60);
|
||||
setCookie('im_livechat_session', unaccent(JSON.stringify(this.messaging.publicLivechatGlobal.publicLivechat.widget.toData()), true), 60 * 60, 'required');
|
||||
this.update({ isOpeningChat: false });
|
||||
},
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import { patchRecordMethods } from '@mail/model/model_core';
|
||||
// ensure that the model definition is loaded before the patch
|
||||
import '@im_livechat/public_models/public_livechat_global';
|
||||
|
||||
import { set_cookie } from 'web.utils';
|
||||
import {setCookie} from 'web.utils.cookies';
|
||||
|
||||
patchRecordMethods('PublicLivechatGlobal', {
|
||||
/**
|
||||
@@ -25,7 +25,7 @@ patchRecordMethods('PublicLivechatGlobal', {
|
||||
return this.loadQWebTemplate();
|
||||
}
|
||||
if (this.options.chat_request_session) {
|
||||
set_cookie('im_livechat_session', JSON.stringify(this.options.chat_request_session), 60 * 60);
|
||||
setCookie('im_livechat_session', JSON.stringify(this.options.chat_request_session), 60 * 60, 'required');
|
||||
}
|
||||
return this._super();
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
odoo.define('website_sale.recently_viewed', function (require) {
|
||||
|
||||
var publicWidget = require('web.public.widget');
|
||||
var utils = require('web.utils');
|
||||
const {getCookie, setCookie} = require('web.utils.cookies');
|
||||
|
||||
publicWidget.registry.productsRecentlyViewedUpdate = publicWidget.Widget.extend({
|
||||
selector: '#product_detail',
|
||||
@@ -33,7 +33,7 @@ publicWidget.registry.productsRecentlyViewedUpdate = publicWidget.Widget.extend(
|
||||
if (! parseInt(this.el.dataset.viewTrack, 10)) {
|
||||
return; // Is not tracked
|
||||
}
|
||||
if (utils.get_cookie(cookieName)) {
|
||||
if (getCookie(cookieName)) {
|
||||
return; // Already tracked in the last 30min
|
||||
}
|
||||
if ($(this.el).find('.js_product.css_not_available').length) {
|
||||
@@ -45,7 +45,7 @@ publicWidget.registry.productsRecentlyViewedUpdate = publicWidget.Widget.extend(
|
||||
product_id: productId,
|
||||
}
|
||||
}).then(function (res) {
|
||||
utils.set_cookie(cookieName, productId, 30 * 60);
|
||||
setCookie(cookieName, productId, 30 * 60, 'optional');
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ odoo.define('website_sale_comparison.comparison', function (require) {
|
||||
var concurrency = require('web.concurrency');
|
||||
var core = require('web.core');
|
||||
var publicWidget = require('web.public.widget');
|
||||
var utils = require('web.utils');
|
||||
const {getCookie, setCookie} = require('web.utils.cookies');
|
||||
var VariantMixin = require('sale.VariantMixin');
|
||||
var website_sale_utils = require('website_sale.utils');
|
||||
const cartHandlerMixin = website_sale_utils.cartHandlerMixin;
|
||||
@@ -28,7 +28,7 @@ var ProductComparison = publicWidget.Widget.extend(VariantMixin, {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
this.product_data = {};
|
||||
this.comparelist_product_ids = JSON.parse(utils.get_cookie('comparelist_product_ids') || '[]');
|
||||
this.comparelist_product_ids = JSON.parse(getCookie('comparelist_product_ids') || '[]');
|
||||
this.product_compare_limit = 4;
|
||||
this.guard = new concurrency.Mutex();
|
||||
},
|
||||
@@ -141,7 +141,7 @@ var ProductComparison = publicWidget.Widget.extend(VariantMixin, {
|
||||
route: '/shop/get_product_data',
|
||||
params: {
|
||||
product_ids: product_ids,
|
||||
cookies: JSON.parse(utils.get_cookie('comparelist_product_ids') || '[]'),
|
||||
cookies: JSON.parse(getCookie('comparelist_product_ids') || '[]'),
|
||||
},
|
||||
}).then(function (data) {
|
||||
self.comparelist_product_ids = JSON.parse(data.cookies);
|
||||
@@ -225,7 +225,7 @@ var ProductComparison = publicWidget.Widget.extend(VariantMixin, {
|
||||
* @private
|
||||
*/
|
||||
_updateCookie: function () {
|
||||
document.cookie = 'comparelist_product_ids=' + JSON.stringify(this.comparelist_product_ids) + '; path=/';
|
||||
setCookie('comparelist_product_ids', JSON.stringify(this.comparelist_product_ids), 24 * 60 * 60 * 365, 'required');
|
||||
this._updateComparelistView();
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -242,3 +242,7 @@ class IrHttp(models.AbstractModel):
|
||||
'multi_lang': len(self.env['res.lang'].sudo().get_installed()) > 1,
|
||||
}
|
||||
return hashlib.sha1(json.dumps(translation_cache, sort_keys=True).encode()).hexdigest()
|
||||
|
||||
@classmethod
|
||||
def _is_allowed_cookie(cls, cookie_type):
|
||||
return True
|
||||
|
||||
@@ -1059,6 +1059,14 @@ class Response(werkzeug.wrappers.Response):
|
||||
self.response.append(self.render())
|
||||
self.template = None
|
||||
|
||||
def set_cookie(self, *args, **kwargs):
|
||||
cookie_type = kwargs.pop('cookie_type', None)
|
||||
if request.db:
|
||||
if not request.env['ir.http']._is_allowed_cookie(cookie_type):
|
||||
kwargs['expires'] = 0
|
||||
kwargs['max_age'] = 0
|
||||
super().set_cookie(*args, **kwargs)
|
||||
|
||||
|
||||
class FutureResponse:
|
||||
"""
|
||||
@@ -1074,6 +1082,11 @@ class FutureResponse:
|
||||
|
||||
@functools.wraps(werkzeug.Response.set_cookie)
|
||||
def set_cookie(self, *args, **kwargs):
|
||||
if 'cookie_type' in kwargs and request.db:
|
||||
cookie_type = kwargs.pop('cookie_type', 'required')
|
||||
if not request.env['ir.http']._is_allowed_cookie(cookie_type):
|
||||
kwargs['expires'] = 0
|
||||
kwargs['max_age'] = 0
|
||||
werkzeug.Response.set_cookie(self, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user