[FIX] im_livechat: matching rule in cache
The problem was that the matching rule was evaluated before sending the html page, and the script was inserted in the page according to the matching rule (it wasn't inserted if the rule was 'hide_button'). However, the matching rule wasn't re-evaluated if the page was already in the cache. The page content thus might depend on a matching rule computed for someone else in that case. Rather than inserting the script according to the matching rule, we insert it only if there is an operator available. We then ask for the matching rule in the livechat widget, by RPC, and we reject its willStart deferred if the rule says so. We also re-check for operator availability in the same RPC.
This commit is contained in:
@@ -29,12 +29,36 @@ class LivechatController(http.Controller):
|
||||
def loader(self, channel_id, **kwargs):
|
||||
username = kwargs.get("username", _("Visitor"))
|
||||
channel = request.env['im_livechat.channel'].sudo().browse(channel_id)
|
||||
info = request.env['im_livechat.channel'].with_context(from_external_page=True).match_rules(request, channel.id, username=username)
|
||||
return request.render('im_livechat.loader', {'info': info, 'web_session_required': True}) if info else False
|
||||
info = request.env['im_livechat.channel'].get_livechat_info(channel.id, username=username)
|
||||
return request.render('im_livechat.loader', {'info': info, 'web_session_required': True}) if info['available'] else False
|
||||
|
||||
@http.route('/im_livechat/available', type='json', auth="public")
|
||||
def available(self, channel_id):
|
||||
return len(request.env['im_livechat.channel'].browse(channel_id).get_available_users())
|
||||
@http.route('/im_livechat/init', type='json', auth="public")
|
||||
def livechat_init(self, channel_id):
|
||||
LivechatChannel = request.env['im_livechat.channel']
|
||||
available = len(LivechatChannel.browse(channel_id).get_available_users())
|
||||
rule = {}
|
||||
if available:
|
||||
# find the country from the request
|
||||
country_id = False
|
||||
country_code = request.session.geoip and request.session.geoip.get('country_code') or False
|
||||
if country_code:
|
||||
country_ids = self.env['res.country'].sudo().search([('code', '=', country_code)])
|
||||
if country_ids:
|
||||
country_id = country_ids[0].id
|
||||
# extract url
|
||||
url = request.httprequest.headers.get('Referer')
|
||||
# find the first matching rule for the given country and url
|
||||
matching_rule = request.env['im_livechat.channel.rule'].sudo().match_rule(channel_id, url, country_id)
|
||||
if matching_rule:
|
||||
rule = {
|
||||
'action': matching_rule.action,
|
||||
'auto_popup_timer': matching_rule.auto_popup_timer,
|
||||
'regex_url': matching_rule.regex_url,
|
||||
}
|
||||
return {
|
||||
'available_for_me': available and (not rule or rule['action'] != 'hide_button'),
|
||||
'rule': rule,
|
||||
}
|
||||
|
||||
@http.route('/im_livechat/get_session', type="json", auth='public')
|
||||
def get_session(self, channel_id, anonymous_name, **kwargs):
|
||||
|
||||
@@ -193,36 +193,13 @@ class ImLivechatChannel(models.Model):
|
||||
}
|
||||
|
||||
@api.model
|
||||
def match_rules(self, request, channel_id, username='Visitor'):
|
||||
info = {
|
||||
'server_url': self.env['ir.config_parameter'].get_param('web.base.url'),
|
||||
'options': self.sudo().get_channel_infos(channel_id),
|
||||
}
|
||||
info['options']["default_username"] = username
|
||||
# find the country from the request
|
||||
country_id = False
|
||||
country_code = request.session.geoip and request.session.geoip.get('country_code') or False
|
||||
if country_code:
|
||||
country_ids = self.env['res.country'].sudo().search([('code', '=', country_code)])
|
||||
if country_ids:
|
||||
country_id = country_ids[0].id
|
||||
# extract url
|
||||
if self.env.context.get('from_external_page', False):
|
||||
url = request.httprequest.headers.get('Referer')
|
||||
else:
|
||||
url = request.httprequest.base_url
|
||||
# find the match rule for the given country and url
|
||||
rule = self.env['im_livechat.channel.rule'].sudo().match_rule(channel_id, url, country_id)
|
||||
if rule:
|
||||
if rule.action == 'hide_button':
|
||||
# don't return the initialization script, since its blocked (in the country)
|
||||
return False
|
||||
rule_data = {
|
||||
'action': rule.action,
|
||||
'auto_popup_timer': rule.auto_popup_timer,
|
||||
'regex_url': rule.regex_url,
|
||||
}
|
||||
info['rule'] = rule and rule_data or False
|
||||
def get_livechat_info(self, channel_id, username='Visitor'):
|
||||
info = {}
|
||||
info['available'] = self.browse(channel_id).get_available_users(),
|
||||
if info['available']:
|
||||
info['server_url'] = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
info['options'] = self.sudo().get_channel_infos(channel_id)
|
||||
info['options']["default_username"] = username
|
||||
return info
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ var LivechatButton = Widget.extend({
|
||||
"click": "open_chat"
|
||||
},
|
||||
|
||||
init: function (parent, server_url, options, rule) {
|
||||
init: function (parent, server_url, options) {
|
||||
this._super(parent);
|
||||
this.options = _.defaults(options || {}, {
|
||||
placeholder: _t('Ask something ...'),
|
||||
@@ -28,7 +28,6 @@ var LivechatButton = Widget.extend({
|
||||
button_text: _t("Chat with one of our collaborators"),
|
||||
default_message: _t("How may I help you?"),
|
||||
});
|
||||
this.rule = rule || {};
|
||||
this.channel = null;
|
||||
this.chat_window = null;
|
||||
this.messages = [];
|
||||
@@ -39,44 +38,41 @@ var LivechatButton = Widget.extend({
|
||||
var cookie = utils.get_cookie('im_livechat_session');
|
||||
var ready;
|
||||
if (!cookie) {
|
||||
ready = session.rpc("/im_livechat/available", {channel_id: this.options.channel_id});
|
||||
ready = session.rpc("/im_livechat/init", {channel_id: this.options.channel_id}).then(function (result) {
|
||||
if (!result.available_for_me) {
|
||||
return $.Deferred().reject();
|
||||
}
|
||||
self.rule = result.rule;
|
||||
});
|
||||
} else {
|
||||
var channel = JSON.parse(cookie);
|
||||
ready = $.when(true, session.rpc("/im_livechat/history", {channel_id: channel.id, limit: 100}));
|
||||
ready = session.rpc("/im_livechat/history", {channel_id: channel.id, limit: 100}).then(function (history) {
|
||||
self.history = history;
|
||||
});
|
||||
}
|
||||
return ready.then(function (available, history) {
|
||||
self.available = available;
|
||||
self.history = history;
|
||||
if (available) {
|
||||
return self.load_qweb_template();
|
||||
}
|
||||
});
|
||||
return ready.then(this.load_qweb_template.bind(this));
|
||||
},
|
||||
|
||||
start: function () {
|
||||
if (!this.available) {
|
||||
this.do_hide();
|
||||
} else {
|
||||
this.$el.text(this.options.button_text);
|
||||
if (this.history) {
|
||||
_.each(this.history.reverse(), this.add_message.bind(this));
|
||||
this.open_chat();
|
||||
} else if (this.rule.action === 'auto_popup') {
|
||||
var auto_popup_cookie = utils.get_cookie('im_livechat_auto_popup');
|
||||
if (!auto_popup_cookie || JSON.parse(auto_popup_cookie)) {
|
||||
this.auto_popup_timeout = setTimeout(this.open_chat.bind(this), this.rule.auto_popup_timer*1000);
|
||||
this.$el.text(this.options.button_text);
|
||||
if (this.history) {
|
||||
_.each(this.history.reverse(), this.add_message.bind(this));
|
||||
this.open_chat();
|
||||
} else if (this.rule.action === 'auto_popup') {
|
||||
var auto_popup_cookie = utils.get_cookie('im_livechat_auto_popup');
|
||||
if (!auto_popup_cookie || JSON.parse(auto_popup_cookie)) {
|
||||
this.auto_popup_timeout = setTimeout(this.open_chat.bind(this), this.rule.auto_popup_timer*1000);
|
||||
}
|
||||
}
|
||||
bus.on('notification', this, function (notification) {
|
||||
if (this.channel && (notification[0] === this.channel.uuid)) {
|
||||
this.add_message(notification[1]);
|
||||
this.render_messages();
|
||||
if (this.chat_window.folded) {
|
||||
this.chat_window.update_unread(this.chat_window.unread_msgs+1);
|
||||
}
|
||||
}
|
||||
bus.on('notification', this, function (notification) {
|
||||
if (this.channel && (notification[0] === this.channel.uuid)) {
|
||||
this.add_message(notification[1]);
|
||||
this.render_messages();
|
||||
if (this.chat_window.folded) {
|
||||
this.chat_window.update_unread(this.chat_window.unread_msgs+1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return this._super();
|
||||
},
|
||||
|
||||
|
||||
@@ -140,10 +140,10 @@
|
||||
<template id="loader" name="Livechat : Javascript appending the livechat button">
|
||||
|
||||
<t t-if="not info">
|
||||
<t t-set="info" t-value="request.env['im_livechat.channel'].match_rules(request, channel)"/>
|
||||
<t t-set="info" t-value="request.env['im_livechat.channel'].get_livechat_info(channel)"/>
|
||||
</t>
|
||||
|
||||
<t t-if="info" t-translation="off">
|
||||
<t t-if="info['available']" t-translation="off">
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
<t t-if="web_session_required">
|
||||
odoo.define('web.session', function (require) {
|
||||
@@ -158,8 +158,7 @@
|
||||
var button = new im_livechat.LivechatButton(
|
||||
$('body'),
|
||||
"<t t-esc="info['server_url']"/>",
|
||||
<t t-raw="json.dumps(info.get('options', {}))"/>,
|
||||
<t t-raw="json.dumps(info.get('rule', False))"/>
|
||||
<t t-raw="json.dumps(info.get('options', {}))"/>
|
||||
);
|
||||
button.appendTo($('body'));
|
||||
window.livechat_button = button;
|
||||
|
||||
Reference in New Issue
Block a user