From d8605b7993d3073e976bba0bba1e61a3f54510f1 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Fri, 18 Dec 2015 11:50:59 +0100 Subject: [PATCH] [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. --- addons/im_livechat/controllers/main.py | 34 +++++++++-- .../im_livechat/models/im_livechat_channel.py | 37 +++--------- .../im_livechat/static/src/js/im_livechat.js | 60 +++++++++---------- .../views/im_livechat_channel_templates.xml | 7 +-- 4 files changed, 67 insertions(+), 71 deletions(-) diff --git a/addons/im_livechat/controllers/main.py b/addons/im_livechat/controllers/main.py index c8006fd2df1..831df1418ae 100644 --- a/addons/im_livechat/controllers/main.py +++ b/addons/im_livechat/controllers/main.py @@ -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): diff --git a/addons/im_livechat/models/im_livechat_channel.py b/addons/im_livechat/models/im_livechat_channel.py index e4733816ba8..8cdaf405219 100644 --- a/addons/im_livechat/models/im_livechat_channel.py +++ b/addons/im_livechat/models/im_livechat_channel.py @@ -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 diff --git a/addons/im_livechat/static/src/js/im_livechat.js b/addons/im_livechat/static/src/js/im_livechat.js index b47ee3726c4..c2f0a37f5ba 100644 --- a/addons/im_livechat/static/src/js/im_livechat.js +++ b/addons/im_livechat/static/src/js/im_livechat.js @@ -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(); }, diff --git a/addons/im_livechat/views/im_livechat_channel_templates.xml b/addons/im_livechat/views/im_livechat_channel_templates.xml index cfcddf9f8d8..d97df04989e 100644 --- a/addons/im_livechat/views/im_livechat_channel_templates.xml +++ b/addons/im_livechat/views/im_livechat_channel_templates.xml @@ -140,10 +140,10 @@