From f13dd8cee762b121778bc8d9a29af3876a8d3fe7 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 28 Jan 2014 17:26:49 +0100 Subject: [PATCH] [FIX][ADD] im, im_livechat: fix security rules and add history when opening a conversation bzr revid: dle@openerp.com-20140128162649-aptjndl85ocmem8a --- addons/im/im.py | 26 +++++++++++-- addons/im/security/im_security.xml | 4 +- addons/im/security/ir.model.access.csv | 2 +- addons/im/static/src/js/im.js | 1 + addons/im/static/src/js/im_common.js | 37 +++++++++++++++---- addons/im/static/src/xml/im_common.xml | 2 +- addons/im_livechat/im_livechat.py | 4 +- addons/im_livechat/im_livechat_view.xml | 17 +++++++++ .../im_livechat/security/ir.model.access.csv | 2 - .../static/ext/static/js/livesupport.js | 13 ++++--- 10 files changed, 84 insertions(+), 24 deletions(-) diff --git a/addons/im/im.py b/addons/im/im.py index 566a2fcca20..5fff89f584d 100644 --- a/addons/im/im.py +++ b/addons/im/im.py @@ -27,7 +27,6 @@ from openerp.addons.web.http import request from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT import datetime from openerp.osv import osv, fields, expression -import time import logging import json import select @@ -202,7 +201,7 @@ class im_session(osv.osv): return res _columns = { - 'user_ids': fields.many2many('im.user'), + 'user_ids': fields.many2many('im.user', 'im_session_im_user_rel', 'im_session_id', 'im_user_id', 'Users'), "name": fields.function(_calc_name, string="Name", type='char'), } @@ -225,6 +224,9 @@ class im_session(osv.osv): }, context=context) return self.read(cr, uid, session_id, context=context) + def get_session_users(self, cr, uid, session_id, context=None): + return self.read(cr, openerp.SUPERUSER_ID, session_id, ['user_ids'], context=context) + def add_to_session(self, cr, uid, session_id, user_id, uuid=None, context=None): my_id = self.pool.get("im.user").get_my_id(cr, uid, uuid, context=context) session = self.read(cr, uid, session_id, context=context) @@ -259,7 +261,7 @@ class im_user(osv.osv): return ['&', ('im_last_status', '=', True), ('im_last_status_update', '>', (current - delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT))] else: return ['|', ('im_last_status', '=', False), ('im_last_status_update', '<=', (current - delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT))] - + # TODO: Remove fields arg in trunk. Also in im.js. def search_users(self, cr, uid, text_search, fields, limit, context=None): my_id = self.get_my_id(cr, uid, None, context) group_employee = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base', 'group_user')[1] @@ -271,7 +273,7 @@ class im_user(osv.osv): if len(found) < limit: found += self.search(cr, uid, [["name", "ilike", text_search], ["id", "<>", my_id], ["uuid", "=", False], ["im_status", "=", False], ["id", "not in", found]], order="name asc", limit=limit-len(found), context=context) - users = self.read(cr, uid, found, fields, context=context) + users = self.read(cr,openerp.SUPERUSER_ID, found, ["name", "user_id", "uuid", "im_status"], context=context) users.sort(key=lambda obj: found.index(obj['id'])) return users @@ -319,6 +321,9 @@ class im_user(osv.osv): continue return res + def get_users(self, cr, uid, ids, context=None): + return self.read(cr,openerp.SUPERUSER_ID, ids, ["name", "im_status", "uuid"], context=context) + _columns = { 'name': fields.function(_get_name, type='char', size=200, string="Name", store=True, readonly=True), 'assigned_name': fields.char(string="Assigned Name", size=200, required=False), @@ -341,3 +346,16 @@ class im_user(osv.osv): ('user_uniq', 'unique (user_id)', 'Only one chat user per OpenERP user.'), ('uuid_uniq', 'unique (uuid)', 'Chat identifier already used.'), ] + +class res_users(osv.osv): + _inherit = "res.users" + + def _get_im_user(self, cr, uid, ids, field_name, arg, context=None): + result = dict.fromkeys(ids, False) + for index, im_user in enumerate(self.pool['im.user'].search_read(cr, uid, domain=[('user_id', 'in', ids)], fields=['name', 'user_id'], context=context)): + result[ids[index]] = im_user.get('user_id') and (im_user['user_id'][0], im_user['name']) or False + return result + + _columns = { + 'im_user_id' : fields.function(_get_im_user, type='many2one', string="IM User", relation="im.user"), + } diff --git a/addons/im/security/im_security.xml b/addons/im/security/im_security.xml index d6b854c8a98..fa6c3602ead 100644 --- a/addons/im/security/im_security.xml +++ b/addons/im/security/im_security.xml @@ -2,10 +2,10 @@ - Can only read messages that you sent or messages sent to you + Can only read messages from a session where user is - ["|", ('to_id.user_id', 'in', [user.id]), ('from_id.user_id', '=', user.id)] + [('session_id.user_ids', 'in', user.im_user_id)] diff --git a/addons/im/security/ir.model.access.csv b/addons/im/security/ir.model.access.csv index 651aa68c1bb..5137990498a 100644 --- a/addons/im/security/ir.model.access.csv +++ b/addons/im/security/ir.model.access.csv @@ -1,4 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_im_message,im.message,model_im_message,base.group_user,1,0,1,0 +access_im_message,im.message,model_im_message,,1,0,1,0 access_im_user,im.user,model_im_user,,1,1,1,0 access_im_session,im.session,model_im_session,,1,0,0,0 \ No newline at end of file diff --git a/addons/im/static/src/js/im.js b/addons/im/static/src/js/im.js index f4b74adebf6..016a2426e76 100644 --- a/addons/im/static/src/js/im.js +++ b/addons/im/static/src/js/im.js @@ -92,6 +92,7 @@ search_changed: function(e) { var users = new instance.web.Model("im.user"); var self = this; + // TODO: Remove fields arg in trunk. Also in im.js. return this.user_search_dm.add(users.call("search_users", [this.get("current_search"), ["name", "user_id", "uuid", "im_status"], USERS_LIMIT], {context:new instance.web.CompoundContext()})).then(function(users) { var logged_users = _.filter(users, function(u) { return !!u.im_status; }); diff --git a/addons/im/static/src/js/im_common.js b/addons/im/static/src/js/im_common.js index 83f92265ec6..59b4df69eb7 100644 --- a/addons/im/static/src/js/im_common.js +++ b/addons/im/static/src/js/im_common.js @@ -145,7 +145,7 @@ function declare($, _, openerp) { if (_.size(no_cache) === 0) def = $.when(); else - def = im_common.connection.model("im.user").call("read", [_.values(no_cache), []]).then(function(users) { + def = im_common.connection.model("im.user").call("get_users", [_.values(no_cache)]).then(function(users) { self.add_to_user_cache(users); }); return def.then(function() { @@ -230,7 +230,8 @@ function declare($, _, openerp) { return self.chat_with_users(users); }); }, - activate_session: function(session_id, focus) { + activate_session: function(session_id, focus, message) { + var self = this; var conv = _.find(this.conversations, function(conv) {return conv.session_id == session_id;}); var def = $.when(); if (! conv) { @@ -244,6 +245,9 @@ function declare($, _, openerp) { this.calc_positions(); this.trigger("new_conversation", conv); }, this)); + def = def.then(function(){ + return self.load_history(conv, message); + }); } if (focus) { def = def.then(function() { @@ -252,13 +256,32 @@ function declare($, _, openerp) { } return def.then(function() {return conv}); }, - received_messages: function(messages) { + load_history: function(conv, message){ + var self = this; + var domain = [["session_id", "=", conv.session_id]]; + if (!_.isUndefined(message)){ + domain.push(["date", "<", message.date]); + } + return im_common.connection.model("im.message").call("search_read", [domain, [], 0, 10]).then(function(messages){ + messages.reverse(); + var users = _.unique(_.map(messages, function(message){ + return message.from_id[0]; + })); + return self.ensure_users(_.without(users, self.me.get("id"))).then(function(){ + return self.received_messages(messages, true); + }); + }); + }, + received_messages: function(messages, seen) { var self = this; var defs = []; var received = false; + if (_.isUndefined(seen)){ + seen = false; + } _.each(messages, function(message) { if (! message.technical) { - defs.push(self.activate_session(message.session_id[0]).then(function(conv) { + defs.push(self.activate_session(message.session_id[0], false, message).then(function(conv) { received = self.my_id !== message.from_id[0]; return conv.received_message(message); })); @@ -269,7 +292,7 @@ function declare($, _, openerp) { } }); return $.when.apply($, defs).then(function(){ - if (! self.get("window_focus") && received) { + if (! self.get("window_focus") && received && !seen) { self.set("waiting_messages", self.get("waiting_messages") + messages.length); self.ting.play(); self.create_ting(); @@ -368,7 +391,7 @@ function declare($, _, openerp) { refresh_users: function() { var self = this; var user_ids; - return im_common.connection.model("im.session").call("read", [self.session_id]).then(function(session) { + return im_common.connection.model("im.session").call("get_session_users", [self.session_id]).then(function(session) { user_ids = _.without(session.user_ids, self.c_manager.me.get("id")); return self.c_manager.ensure_users(user_ids); }).then(function(users) { @@ -449,7 +472,7 @@ function declare($, _, openerp) { date = "" + zpad(date.getHours(), 2) + ":" + zpad(date.getMinutes(), 2); var to_show = _.map(items, im_common.escape_keep_url); this.last_bubble = $(openerp.qweb.render("im_common.conversation_bubble", {"items": to_show, "user": user, "time": date})); - $(this.$(".oe_im_chatview_content").children()[0]).append(this.last_bubble); + $(this.$(".oe_im_chatview_conversation")).append(this.last_bubble); this._go_bottom(); }, _go_bottom: function() { diff --git a/addons/im/static/src/xml/im_common.xml b/addons/im/static/src/xml/im_common.xml index 462e242befd..efaaf602577 100644 --- a/addons/im/static/src/xml/im_common.xml +++ b/addons/im/static/src/xml/im_common.xml @@ -11,7 +11,7 @@ All users are offline. They will receive your messages on their next connection.
-
+