Merge lp:~openerp-dev/openobject-addons/trunk-chat-feature into lp:openobject-addons

Proposed by Vidhin Mehta (OpenERP)
Status: Needs review
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-chat-feature
Merge into: lp:openobject-addons
Diff against target: 1419 lines (+960/-57)
23 files modified
im/doc/changelog.rst (+14/-0)
im/doc/im_hashtag_message.rst (+22/-0)
im/doc/index.rst (+22/-0)
im/im.py (+44/-4)
im/security/im_security.xml (+11/-0)
im/security/ir.model.access.csv (+2/-1)
im/static/src/css/im_common.css (+61/-1)
im/static/src/js/im.js (+3/-1)
im/static/src/js/im_common.js (+142/-10)
im/static/src/xml/im_common.xml (+56/-1)
im_livechat/__openerp__.py (+4/-0)
im_livechat/doc/changelog.rst (+21/-0)
im_livechat/doc/im_feedback.rst (+29/-0)
im_livechat/doc/im_livechat_channel_session.rst (+34/-0)
im_livechat/doc/index.rst (+30/-0)
im_livechat/im_livechat.py (+131/-2)
im_livechat/im_livechat_demo.xml (+44/-0)
im_livechat/im_livechat_view.xml (+203/-35)
im_livechat/security/ir.model.access.csv (+8/-0)
im_livechat/static/ext/static/css/im_livechat.css (+39/-0)
im_livechat/static/ext/static/js/livesupport.js (+1/-1)
im_livechat/test/test_im_livechat.yml (+39/-0)
im_livechat/web_page.html (+0/-1)
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/trunk-chat-feature
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+185263@code.launchpad.net
To post a comment you must log in.
8921. By Ishwar Malvi(OpenERP)

[IMP]improved typo and code for chat_history action.

8922. By Ishwar Malvi(OpenERP)

[IMP]improved code for hashtag message.

8923. By Ishwar Malvi(OpenERP)

[IMP]added yml test for im_livechat.

8924. By Ishwar Malvi(OpenERP)

[IMP]improved typo and space.

8925. By Ishwar Malvi(OpenERP)

[MERGE]with trunk.

8926. By Ishwar Malvi(OpenERP)

[IMP]improved css for livechat channel kanban.

Unmerged revisions

8926. By Ishwar Malvi(OpenERP)

[IMP]improved css for livechat channel kanban.

8925. By Ishwar Malvi(OpenERP)

[MERGE]with trunk.

8924. By Ishwar Malvi(OpenERP)

[IMP]improved typo and space.

8923. By Ishwar Malvi(OpenERP)

[IMP]added yml test for im_livechat.

8922. By Ishwar Malvi(OpenERP)

[IMP]improved code for hashtag message.

8921. By Ishwar Malvi(OpenERP)

[IMP]improved typo and code for chat_history action.

8920. By Ishwar Malvi(OpenERP)

[MERGE]with trunk.

8919. By Kunal Chavda

[MERGE] refactor code.

8918. By Ishwar Malvi(OpenERP)

[MERGE]with trunk.

8917. By Ishwar Malvi(OpenERP)

[IMP]improved code.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'im/doc'
2=== added file 'im/doc/changelog.rst'
3--- im/doc/changelog.rst 1970-01-01 00:00:00 +0000
4+++ im/doc/changelog.rst 2014-01-15 16:16:23 +0000
5@@ -0,0 +1,14 @@
6+.. _changelog:
7+
8+Changelog
9+=========
10+
11+`trunk`
12+----------------
13+
14+- im.user update
15+
16+ - ``get_hashtags``: Added method to get hashtag messages of individual user.
17+ - Value: ids
18+ - Return: List of dictionary of hashtag message with it's description.
19+
20
21=== added file 'im/doc/im_hashtag_message.rst'
22--- im/doc/im_hashtag_message.rst 1970-01-01 00:00:00 +0000
23+++ im/doc/im_hashtag_message.rst 2014-01-15 16:16:23 +0000
24@@ -0,0 +1,22 @@
25+.. _im_hashtag_message:
26+
27+im.hashtag.message
28+============
29+
30+Models
31+++++++
32+
33+``im.hashtag.message`` is a model for holding attributes for hashtag message.
34+
35+
36+Fields
37+++++++
38+- ``user_id``: Id of responsible user for hashtag message
39+- ``hashtag``: Hashtag message must be start with hash(#)
40+- ``note``: Descripton of hashtag message
41+
42+Methods
43++++++++
44+- ``_check_hashtag``:
45+ - Value: ids
46+ - Return: True when hashtag start with # else False.
47\ No newline at end of file
48
49=== added file 'im/doc/index.rst'
50--- im/doc/index.rst 1970-01-01 00:00:00 +0000
51+++ im/doc/index.rst 2014-01-15 16:16:23 +0000
52@@ -0,0 +1,22 @@
53+=====================
54+Im DevDoc
55+=====================
56+
57+Im module documentation
58+===================================
59+
60+Changelog
61+'''''''''
62+
63+.. toctree::
64+ :maxdepth: 1
65+
66+ changelog.rst
67+
68+Im Hashtag Message
69+'''''''''
70+
71+.. toctree::
72+ :maxdepth: 1
73+
74+ im_hashtag_message.rst
75
76=== modified file 'im/im.py'
77--- im/im.py 2013-10-22 17:06:59 +0000
78+++ im/im.py 2014-01-15 16:16:23 +0000
79@@ -31,6 +31,12 @@
80 from openerp.http import request
81 from openerp.osv import osv, fields
82 from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
83+from openerp.tools.translate import _
84+import datetime
85+import time
86+import logging
87+import json
88+import select
89
90 _logger = logging.getLogger(__name__)
91
92@@ -191,6 +197,30 @@
93 'to_id': [(6, 0, to_ids)], 'session_id': to_session_id, 'technical': technical}, context=context)
94 notify_channel(cr, "im_channel", {'type': 'message', 'receivers': [my_id] + to_ids})
95 return False
96+
97+class im_hashtag_message(osv.osv):
98+ _name= "im.hashtag.message"
99+
100+ _defaults = {
101+ 'user_id': lambda obj, cr, uid, context: uid,
102+ 'hashtag': '#'
103+ }
104+
105+ _columns = {
106+ 'user_id': fields.many2one("res.users","User", select=True, ondelete='cascade'),
107+ 'hashtag': fields.char("Hashtag Message", required=True),
108+ 'note': fields.text("Message", required=True, translate=True),
109+ }
110+
111+ def _check_hashtag(self, cr, uid, ids, context=None):
112+ for l in self.browse(cr, uid, ids, context=context):
113+ if not l.hashtag[:1] == "#":
114+ return False
115+ return True
116+
117+ _constraints = [
118+ (_check_hashtag, 'Hashtag start with "#" sign will be allowed.', ['hashtag'])
119+ ]
120
121 class im_session(osv.osv):
122 _name = 'im.session'
123@@ -200,12 +230,11 @@
124 for obj in self.browse(cr, uid, ids, context=context):
125 res[obj.id] = ", ".join([x.name for x in obj.user_ids])
126 return res
127-
128+
129 _columns = {
130 'user_ids': fields.many2many('im.user'),
131- "name": fields.function(_calc_name, string="Name", type='char'),
132+ 'name': fields.function(_calc_name, string='Name', type='char'),
133 }
134-
135 # Todo: reuse existing sessions if possible
136 def session_get(self, cr, uid, users_to, uuid=None, context=None):
137 my_id = self.pool.get("im.user").get_my_id(cr, uid, uuid, context=context)
138@@ -215,11 +244,13 @@
139 domain.append(('user_ids', 'in', [user_to]))
140 sids = self.search(cr, openerp.SUPERUSER_ID, domain, context=context, limit=1)
141 session_id = None
142+ im_feedback_obj = self.pool.get('im.feedback')
143 for session in self.browse(cr, uid, sids, context=context):
144+ feed_ids = im_feedback_obj.search(cr, uid, [('session_id','=', session.id),('feedback','!=',None)])
145 if len(session.user_ids) == len(users):
146 session_id = session.id
147 break
148- if not session_id:
149+ if not session_id and users_to or feed_ids:
150 session_id = self.create(cr, openerp.SUPERUSER_ID, {
151 'user_ids': [(6, 0, users)]
152 }, context=context)
153@@ -249,6 +280,15 @@
154 res[obj["id"]] = obj["im_last_status"] and (last_update + delta) > current
155 return res
156
157+ def get_hashtags(self, cr, uid, ids, context):
158+ res={}
159+ im_hashtag_message_obj = self.pool.get('im.hashtag.message')
160+ im_user_id = self.browse(cr, uid, ids, context=context).user_id
161+ hashtags_ids = im_hashtag_message_obj.search(cr, uid, ['|',('user_id','=', None),('user_id','=', im_user_id.id)])
162+ for data in im_hashtag_message_obj.browse(cr, uid, hashtags_ids, context=context):
163+ res[data.hashtag] = data.note
164+ return res
165+
166 def search_users(self, cr, uid, text_search, fields, limit, context=None):
167 my_id = self.get_my_id(cr, uid, None, context)
168 found = self.search(cr, uid, [["name", "ilike", text_search], ["id", "<>", my_id], ["uuid", "=", False]],
169
170=== modified file 'im/security/im_security.xml'
171--- im/security/im_security.xml 2013-09-02 12:23:11 +0000
172+++ im/security/im_security.xml 2014-01-15 16:16:23 +0000
173@@ -22,5 +22,16 @@
174 <field name="perm_create" eval="1"/>
175 <field name="perm_unlink" eval="1"/>
176 </record>
177+
178+ <record id="hashtag_rule_1" model="ir.rule">
179+ <field name="name">Can create, read and modify hashtag message of his/her and unassigned </field>
180+ <field name="model_id" ref="model_im_hashtag_message"/>
181+ <field name="domain_force">["|", ('user_id', '=', user.id),('user_id', '=', False)]</field>
182+ <field name="perm_unlink" eval="1"/>
183+ <field name="perm_write" eval="1"/>
184+ <field name="perm_read" eval="1"/>
185+ <field name="perm_create" eval="1"/>
186+ </record>
187+
188 </data>
189 </openerp>
190
191=== modified file 'im/security/ir.model.access.csv'
192--- im/security/ir.model.access.csv 2013-09-02 12:23:11 +0000
193+++ im/security/ir.model.access.csv 2014-01-15 16:16:23 +0000
194@@ -1,4 +1,5 @@
195 id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
196 access_im_message,im.message,model_im_message,base.group_user,1,0,1,0
197 access_im_user,im.user,model_im_user,,1,1,1,0
198-access_im_session,im.session,model_im_session,,1,0,0,0
199\ No newline at end of file
200+access_im_session,im.session,model_im_session,,1,1,1,0
201+access_im_hashtag_message,access_im_hashtag_message,model_im_hashtag_message,,1,1,1,0
202\ No newline at end of file
203
204=== modified file 'im/static/src/css/im_common.css'
205--- im/static/src/css/im_common.css 2013-09-02 16:08:11 +0000
206+++ im/static/src/css/im_common.css 2014-01-15 16:16:23 +0000
207@@ -73,7 +73,7 @@
208 border-bottom: 1px solid #AEB9BD;
209 cursor: pointer;
210 }
211-.oe_im_chatview .oe_im_chatview_close {
212+.oe_im_chatview .oe_im_chatview_close,.oe_im_chatview .oe_im_chatview_add {
213 padding: 0;
214 cursor: pointer;
215 background: transparent;
216@@ -187,3 +187,63 @@
217 width: 11px;
218 height: 11px;
219 }
220+.oe_im_cancel_people {
221+ float: right;
222+}
223+.oe_im_user_avatar_bubble {
224+ width: 22px;
225+ height: 22px;
226+}
227+
228+/* feedback */
229+
230+.oe_im_feedback_notify, .oe_im_feedback_back {
231+ margin-top: 80px;
232+ color: #FFFFFF;
233+}
234+.oe_im_feedback_notify a, .oe_im_feedback_back a{
235+ cursor: pointer;
236+ text-decoration: underline;
237+ margin-left:15px;
238+}
239+.oe_im_feedback {
240+ margin-left: 35px;
241+ margin-top: 15px;
242+}
243+.oe_im_feedback a {
244+ margin-left: 10px;
245+ cursor: pointer;
246+}
247+
248+/* feedback reason*/
249+
250+.oe_im_feedback_reason_lbl {
251+ margin-top: 45px;
252+ color: #FFFFFF;
253+ width: 95%;
254+ font-size: 9pt;
255+ padding-left: 10px;
256+}
257+.oe_im_feedback_reason_txt {
258+ padding: 30px;
259+}
260+.oe_im_req_validation {
261+ display: none;
262+ color: #FC2929;
263+ text-shadow: none;
264+ font-weight: bold;
265+}
266+.oe_im_feedback_reason_txt textarea {
267+ width: 180px;
268+ height: 55px;
269+}
270+.oe_im_feedback_reason_btn {
271+ padding-left: 60px;
272+ padding-bottom: 50px;
273+}
274+.oe_im_reason_btn {
275+ width: 60px;
276+}
277+.oe_chatter_checkbox{
278+ float: right;
279+}
280
281=== added file 'im/static/src/img/bad.png'
282Binary files im/static/src/img/bad.png 1970-01-01 00:00:00 +0000 and im/static/src/img/bad.png 2014-01-15 16:16:23 +0000 differ
283=== added file 'im/static/src/img/good.png'
284Binary files im/static/src/img/good.png 1970-01-01 00:00:00 +0000 and im/static/src/img/good.png 2014-01-15 16:16:23 +0000 differ
285=== added file 'im/static/src/img/groupdefault.png'
286Binary files im/static/src/img/groupdefault.png 1970-01-01 00:00:00 +0000 and im/static/src/img/groupdefault.png 2014-01-15 16:16:23 +0000 differ
287=== added file 'im/static/src/img/ok.png'
288Binary files im/static/src/img/ok.png 1970-01-01 00:00:00 +0000 and im/static/src/img/ok.png 2014-01-15 16:16:23 +0000 differ
289=== modified file 'im/static/src/js/im.js'
290--- im/static/src/js/im.js 2013-12-02 13:24:45 +0000
291+++ im/static/src/js/im.js 2014-01-15 16:16:23 +0000
292@@ -54,7 +54,7 @@
293 this.set("right_offset", 0);
294 this.set("current_search", "");
295 this.users = [];
296- this.c_manager = new im_common.ConversationManager(this);
297+ this.c_manager = new im_common.ConversationManager(this, {snippet: true, enable_chatroom: true});
298 window.im_conversation_manager = this.c_manager;
299 this.on("change:right_offset", this.c_manager, _.bind(function() {
300 this.c_manager.set("right_offset", this.get("right_offset"));
301@@ -68,6 +68,8 @@
302 $(window).resize(_.bind(this.calc_box, this));
303 this.calc_box();
304 this.on("change:current_search", this, this.search_changed);
305+ this.search_changed();
306+
307 return this.c_manager.start_polling().then(function() {
308 self.c_manager.on("new_conversation", self, function(conv) {
309 conv.$el.droppable({
310
311=== modified file 'im/static/src/js/im_common.js'
312--- im/static/src/js/im_common.js 2013-09-11 16:34:52 +0000
313+++ im/static/src/js/im_common.js 2014-01-15 16:16:23 +0000
314@@ -57,12 +57,16 @@
315 im_common.ConversationManager = openerp.Class.extend(openerp.PropertiesMixin, {
316 init: function(parent, options) {
317 openerp.PropertiesMixin.init.call(this, parent);
318+ this.setParent(parent);
319 this.options = _.clone(options) || {};
320 _.defaults(this.options, {
321 inputPlaceholder: _t("Say something..."),
322 defaultMessage: null,
323 userName: _t("Anonymous"),
324- anonymous_mode: false
325+ anonymous_mode: false,
326+ snippet: false,
327+ enable_chatroom: false,
328+ feedback: false
329 });
330 this.set("right_offset", 0);
331 this.set("bottom_offset", 0);
332@@ -296,7 +300,11 @@
333 events: {
334 "keydown input": "keydown",
335 "click .oe_im_chatview_close": "close",
336- "click .oe_im_chatview_header": "show_hide"
337+ "click .oe_im_chatview_header": "show_hide",
338+ "click .oe_im_chatview_add": "invite_people",
339+ "click .oe_im_chatview_bubble button": "start_chat",
340+ "click .oe_im_feedback_back a": "back_to_chat",
341+ "click .oe_im_feedback a": "submit_feedback"
342 },
343 init: function(parent, c_manager, session_id, options) {
344 this._super(parent);
345@@ -307,14 +315,16 @@
346 this.set("bottom_position", 0);
347 this.shown = true;
348 this.set("pending", 0);
349- this.inputPlaceholder = this.options.defaultInputPlaceholder;
350+ this.inputPlaceholder = this.options.inputPlaceholder;
351 this.set("users", []);
352 this.set("disconnected", false);
353 this.others = [];
354+ this.hashtags = null;
355+ this.feedback_fillup = false;
356 },
357 start: function() {
358 var self = this;
359-
360+
361 self.$().append(openerp.qweb.render("im_common.conversation", {widget: self}));
362 this.$().hide();
363
364@@ -359,8 +369,7 @@
365 self.$(".oe_im_chatview_nbr_messages").text("(" + self.get("pending") + ")");
366 }
367 }, self));
368-
369- return this.refresh_users().then(function() {
370+ return $.when(this.load_hashtags(), this.refresh_users()).done(function(){
371 self.$().show();
372 });
373 },
374@@ -408,9 +417,22 @@
375 this._add_bubble(user, message.message, openerp.str_to_datetime(message.date));
376 }, this));
377 },
378+ check_convert: function(){
379+ var self = this;
380+ var terms = _.keys(this.hashtags);
381+ var values = this.split(this.$("input").val());
382+ var new_list = [];
383+ _.each(values, function(value){
384+ new_list.push((_.contains(terms, value))?self.hashtags[value]:value)
385+ });
386+ this.$("input").val(new_list.join(" "))
387+ },
388 keydown: function(e) {
389 if(e && e.which !== 13) {
390+ if(this.options.snippet)this.do_convert_hashtag_action(e);
391 return;
392+ }else if(this.options.snippet){
393+ this.check_convert();
394 }
395 var mes = this.$("input").val();
396 if (! mes.trim()) {
397@@ -462,18 +484,66 @@
398 this.send_message(JSON.stringify({"type": "session_modified", "action": "added", "user_id": user.get("id")}), true);
399 }, this));
400 },
401+ split: function (val) {
402+ return val.split(/ \s*/);
403+ },
404+ extractLast: function (term) {
405+ return this.split(term).pop();
406+ },
407+ do_convert_hashtag_action: function(e) {
408+ var self = this;
409+ $(".oe_im_chatview_footer input").bind( "keydown", function( event ) {
410+ if(event.keyCode === 13 && !$( this ).data( "ui-autocomplete" ).menu.active){
411+ $( ".oe_im_chatview_footer input" ).blur().focus();
412+ }
413+ if ( event.keyCode === $.ui.keyCode.TAB &&
414+ $( this ).data( "ui-autocomplete" ).menu.active ) {
415+ event.preventDefault();
416+ }
417+ }).autocomplete({
418+ minLength: 1,
419+ source: function(request, response) {
420+ if(self.extractLast(request.term).match('#')){
421+ response($.ui.autocomplete.filter(_.keys(self.hashtags), self.extractLast(request.term)));
422+ } else {
423+ $( ".oe_im_chatview_footer input" ).blur().focus();
424+ return false;
425+ }
426+ },
427+ focus: function() {
428+ // prevent value inserted on focus
429+ return false;
430+ },
431+ select: function(event, ui) {
432+ var terms = self.split(this.value);
433+ terms.pop();
434+ terms.push(self.hashtags[ui.item.value]);
435+ this.value = terms.join(" ");
436+ return false;
437+ }
438+ });
439+ var position = $(".oe_im_chatview_footer input").autocomplete( "option", "position" );
440+ $(".oe_im_chatview_footer input").autocomplete( "option", "position", { my : "right top", at: "right bottom" } );
441+ },
442 focus: function() {
443 this.$(".oe_im_chatview_input").focus();
444 if (! this.shown)
445 this.show_hide();
446 },
447- close: function() {
448+ close: function(event) {
449+ var self = this;
450+ if(this.options.feedback && !this.feedback_fillup){
451+ this.toggle_class();
452+ this.$el.find(".oe_im_chatview_content").after(openerp.qweb.render("conversation_feedback"));
453+ event.stopPropagation();
454+ return
455+ }
456 var def = $.when();
457 if (this.get("users").length > 1) {
458 def = im_common.connection.model("im.session").call("remove_me_from_session",
459 [this.session_id, this.c_manager.me.get("uuid")]).then(_.bind(function() {
460- return this.send_message(JSON.stringify({"type": "session_modified", "action": "removed",
461- "user_id": this.c_manager.me.get("id")}), true)
462+ return self.send_message(JSON.stringify({"type": "session_modified", "action": "removed",
463+ "user_id": self.c_manager.me.get("id")}), true)
464 }, this))
465 }
466
467@@ -481,6 +551,68 @@
468 this.destroy();
469 }, this));
470 },
471+ invite_people:function(e){
472+ e.stopPropagation();
473+ this.toggle_class();
474+ this.$el.find(".oe_im_chatview_content").after($(openerp.qweb.render("InvitePeople", {"widget": this, 'invited_ids':_.map(this.get('users'),function(user){ return user.get('id')})})));
475+ },
476+ toggle_class: function(){
477+ this.$el.find(".oe_im_chatview_content").toggle();
478+ this.$el.find(".oe_im_chatview_footer").toggle();
479+ this.$el.find(".oe_im_chatview_header button").toggle();
480+ },
481+ load_hashtags: function(){
482+ if(!this.options.snippet) return null;
483+ var self = this;
484+ return (new openerp.web.Model("im.user")).call("get_hashtags", [this.c_manager.me.get('id')], {context : new openerp.web.CompoundContext()
485+ }).then(function(res) {
486+ if(res)self.hashtags = res;
487+ });
488+ },
489+ back_to_chat: function(){
490+ this.$el.find(".oe_im_chatview_content:last").remove();
491+ this.toggle_class();
492+ },
493+ submit_feedback:function(e){
494+ var self = this;
495+ var model = im_common.connection.model("im.feedback");
496+ var feedback_value = parseInt($(e.currentTarget).attr('value'));
497+ model.call("save_feedback", [{session_id: self.session_id,feedback: String(feedback_value)}])
498+ .then(function(feedback_id){
499+ if(feedback_value < 10){
500+ self.$el.find(".oe_im_chatview_content:last").replaceWith(openerp.qweb.render("feedback_reason"));
501+ self.$el.find(":button").click(function(e){
502+ var reason = $(self.$el.find("#reason")).val();
503+ if (e.currentTarget.id == 'submit') {
504+ if (reason.length) {
505+ model.call("write", [[feedback_id], {'reason':reason}],{context: {}});
506+ } else {
507+ self.$el.find('.oe_im_req_validation').show();
508+ return false
509+ }
510+ }
511+ self.feedback_fillup = true;
512+ self.close();
513+ });
514+ }else if(feedback_value == 10){
515+ self.feedback_fillup = true
516+ self.close();
517+ }
518+ });
519+ this.$el.find("#reason").bind("keydown", function() {
520+ self.$el.find('.oe_im_req_validation').hide();
521+ });
522+ },
523+ start_chat: function(e){
524+ var self = this;
525+ this.toggle_class();
526+ var chat_user = this.$el.find(".oe_im_chatview_content:last").remove();
527+ var parent = this.getParent();
528+ $(chat_user).find("input[type='checkbox']:checked").each( function(key, value){
529+ self.add_user(parent.get_user(parseInt($(value).val())));
530+ });
531+ },
532+
533 destroy: function() {
534 _.each(this.get("users"), function(user) {
535 user.remove_watcher();
536@@ -520,7 +652,7 @@
537 txt += _.escape(str.slice(last, result.index));
538 last = url_regex.lastIndex;
539 var url = _.escape(result[0]);
540- txt += '<a href="' + url + '">' + url + '</a>';
541+ txt += '<a target="_blank" href="' + url + '">' + url + '</a>';
542 }
543 txt += _.escape(str.slice(last, str.length));
544 return txt;
545
546=== modified file 'im/static/src/xml/im_common.xml'
547--- im/static/src/xml/im_common.xml 2013-09-03 13:59:40 +0000
548+++ im/static/src/xml/im_common.xml 2014-01-15 16:16:23 +0000
549@@ -6,6 +6,7 @@
550 <span class="oe_im_chatview_users"/>
551 <scan class="oe_im_chatview_nbr_messages" />
552 <button class="oe_im_chatview_close">×</button>
553+ <button t-if="widget.options.enable_chatroom" class="oe_im_chatview_add">+</button>
554 </div>
555 <div class="oe_im_chatview_disconnected">
556 All users are offline. They will receive your messages on their next connection.
557@@ -39,4 +40,58 @@
558 <div class="oe_im_chatview_time"><t t-esc="time"/></div>
559 </div>
560 </t>
561-</templates>
562\ No newline at end of file
563+<t t-name="InvitePeople">
564+ <div class="oe_im_chatview_content">
565+ <t t-set="users" t-value="(widget.getParent()).getParent()['users']"/>
566+ <div class = "oe_im_chatview_bubble" t-foreach="users" t-as="user">
567+ <img class="oe_im_user_avatar_bubble oe_right" t-att-src='user.user.get("image_url")' />
568+ <t t-esc='user.user.get("name")'/>
569+ <input class="oe_chatter_checkbox" t-if= "_.contains(invited_ids, user.user.get('id'))" checked="checked" onclick="return false" type="checkbox" t-att-name= 'user.user.get("name")' t-att-value='user.user.get("id")'>
570+ </input>
571+ <input class="oe_chatter_checkbox" t-if= "!_.contains(invited_ids, user.user.get('id'))" type="checkbox" t-att-name= 'user.user.get("name")' t-att-value='user.user.get("id")'>
572+ </input>
573+ </div>
574+ <div class="oe_im_chatview_bubble">
575+ <t t-if="users.length gt 0">
576+ <button class = "oe_im_submit_people"> Start Chat </button>
577+ <button class = "oe_im_cancel_people"> Cancel </button>
578+ </t>
579+ <t t-if="users.length == 0">
580+ <span>No more member is available.</span>
581+ <button style="float:none !important" class = "oe_im_cancel_people"> Back </button>
582+ </t>
583+ </div>
584+ </div>
585+</t>
586+<t t-name="conversation_feedback">
587+ <div class="oe_im_chatview_content">
588+ <div class="oe_im_feedback_notify">
589+ Please take a second to rate my reply...
590+ </div>
591+ <div class="oe_im_feedback">
592+ <a value="10" name="good" title="It was Good."><img src='/im/static/src/img/good.png'/></a>
593+ <a value="5" name="ok" title="It was OK."><img src='/im/static/src/img/ok.png'/></a>
594+ <a value="1" name="bad" title="It was bad."><img src='/im/static/src/img/bad.png'/></a>
595+ </div>
596+ <div class="oe_im_feedback_back">
597+ <a id="back_to_chat">or back to chat</a>
598+ </div>
599+ </div>
600+</t>
601+ <t t-name="feedback_reason">
602+ <div class="oe_im_chatview_content">
603+ <div class="oe_im_feedback_reason_lbl">
604+ Please give me reason for your feedback...
605+ </div>
606+ <div class="oe_im_feedback_reason_txt">
607+ <textarea id="reason"></textarea>
608+ <div class="oe_im_req_validation">*Please enter valid reason.</div>
609+ </div>
610+ <div class="oe_im_feedback_reason_btn">
611+ <input class="oe_im_reason_btn" type="button" id="submit" value="Submit" />
612+ <input class="oe_im_reason_btn" type="button" id="close" value="Close" />
613+ </div>
614+ </div>
615+ </t>
616+
617+</templates>
618
619=== modified file 'im_livechat/__openerp__.py'
620--- im_livechat/__openerp__.py 2013-03-15 11:21:53 +0000
621+++ im_livechat/__openerp__.py 2014-01-15 16:16:23 +0000
622@@ -22,7 +22,11 @@
623 'demo': [
624 "im_livechat_demo.xml",
625 ],
626+ 'test':[
627+ "test/test_im_livechat.yml"
628+ ],
629 'depends' : ["im", "mail", "portal_anonymous"],
630+ 'css': ['static/ext/static/css/*.css'],
631 'installable': True,
632 'auto_install': False,
633 'application': True,
634
635=== added directory 'im_livechat/doc'
636=== added file 'im_livechat/doc/changelog.rst'
637--- im_livechat/doc/changelog.rst 1970-01-01 00:00:00 +0000
638+++ im_livechat/doc/changelog.rst 2014-01-15 16:16:23 +0000
639@@ -0,0 +1,21 @@
640+.. _changelog:
641+
642+Changelog
643+=========
644+
645+`trunk`
646+----------------
647+
648+- im_livechat.channel update
649+
650+ - ``hashtag_channel_ids``: field added which allow to access hashtag message created for individual channel.
651+ - ``channel_ids``: field added to access number of chats done in individual channel.
652+
653+ - ``_start_channel_session``: method added to create a session every time when join the channel.
654+
655+- im_hashtag_message update
656+
657+ - ``channel_id``: field added to access hashtag message for individual channel.
658+
659+
660+
661
662=== added file 'im_livechat/doc/im_feedback.rst'
663--- im_livechat/doc/im_feedback.rst 1970-01-01 00:00:00 +0000
664+++ im_livechat/doc/im_feedback.rst 2014-01-15 16:16:23 +0000
665@@ -0,0 +1,29 @@
666+.. _im_feedback:
667+
668+im.feedback
669+============
670+
671+Models
672+++++++
673+
674+``im.feedback`` is a model for holding attribute for managing feedback and reason from individual chat session.
675+
676+
677+Fields
678+++++++
679+- ``session_id``: Id of session
680+- ``feedback``: Feedback value
681+- ``reason``: Feedback reason
682+- ``feedback_date``: Date of feedback
683+- ``feedback_id``: Id of chat session
684+
685+Methods
686++++++++
687+
688+- ``save_feedback`` :
689+ - Value: data
690+ - Return: id of record
691+
692+- ``action_chat_history`` :
693+ - Value: ids
694+ - Return: action
695
696=== added file 'im_livechat/doc/im_livechat_channel_session.rst'
697--- im_livechat/doc/im_livechat_channel_session.rst 1970-01-01 00:00:00 +0000
698+++ im_livechat/doc/im_livechat_channel_session.rst 2014-01-15 16:16:23 +0000
699@@ -0,0 +1,34 @@
700+.. _im_livechat_channel_session:
701+
702+im_livechat.channel.session
703+============
704+
705+Models
706+++++++
707+
708+``im_livechat.channel.session`` is a model for holding attribute for managing individual chat session from join to quit the channel.
709+
710+
711+Fields
712+++++++
713+- ``user_id``: Id of responsible user for chat session
714+- ``channel_id``: Id of channel used for chat session
715+- ``start_date``: Start date of chat session
716+- ``end_date``: End date of chat session
717+- ``duration``: Duration of chat session
718+- ``channel_name``: Channel name that is related to channel_id
719+- ``responsible_name``: Responsible name that is related to user_id
720+- ``feedback_ids``: Allows to access all feedback get from chat sessions
721+- ``feedbacks``: Computed from feedback_ids
722+
723+
724+Methods
725++++++++
726+
727+- ``_compute_feedback`` :
728+ - Value: ids
729+ - Return: List of dictionary of feedback and reason.
730+
731+- ``_compute_duration`` :
732+ - Value: ids
733+ - Return: List of dictionary of duration.
734
735=== added file 'im_livechat/doc/index.rst'
736--- im_livechat/doc/index.rst 1970-01-01 00:00:00 +0000
737+++ im_livechat/doc/index.rst 2014-01-15 16:16:23 +0000
738@@ -0,0 +1,30 @@
739+=====================
740+Im Livechat DevDoc
741+=====================
742+
743+Im Livechat module documentation
744+===================================
745+
746+Changelog
747+'''''''''
748+
749+.. toctree::
750+ :maxdepth: 1
751+
752+ changelog.rst
753+
754+Im Feedback
755+'''''''''
756+
757+.. toctree::
758+ :maxdepth: 1
759+
760+ im_feedback.rst
761+
762+Livechat Channel Session
763+'''''''''
764+
765+.. toctree::
766+ :maxdepth: 1
767+
768+ im_livechat_channel_session.rst
769\ No newline at end of file
770
771=== modified file 'im_livechat/im_livechat.py'
772--- im_livechat/im_livechat.py 2013-12-04 13:00:23 +0000
773+++ im_livechat/im_livechat.py 2014-01-15 16:16:23 +0000
774@@ -27,6 +27,9 @@
775 import openerp.addons.im.im as im
776 from openerp.osv import osv, fields
777 from openerp import tools
778+from datetime import datetime
779+import time
780+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DF
781 from openerp import http
782 from openerp.http import request
783
784@@ -118,9 +121,10 @@
785 res[record.id] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url') + \
786 "/im_livechat/web_page?p=" + json.dumps({"db":cr.dbname, "channel":record.id})
787 return res
788-
789+
790 _columns = {
791 'name': fields.char(string="Channel Name", size=200, required=True),
792+ 'hashtag_channel_ids' : fields.one2many('im.hashtag.message', 'channel_id', 'Hashtag Channels'),
793 'user_ids': fields.many2many('res.users', 'im_livechat_channel_im_user', 'channel_id', 'user_id', string="Users"),
794 'are_you_inside': fields.function(_are_you_inside, type='boolean', string='Are you inside the matrix?', store=False),
795 'script': fields.function(_script, type='text', string='Script', store=False),
796@@ -147,6 +151,7 @@
797 help="Small-sized photo of the group. It is automatically "\
798 "resized as a 64x64px image, with aspect ratio preserved. "\
799 "Use this field anywhere a small image is required."),
800+ 'channel_ids': fields.one2many('im_livechat.channel.session', 'channel_id', 'Channel Ids', ondelete='cascade'),
801 }
802
803 def _default_user_ids(self, cr, uid, context=None):
804@@ -199,12 +204,51 @@
805 "channelName": chan.name,
806 }
807
808+ def _start_channel_session(self, cr, uid, ids, user_id=None, context=None):
809+ vals = {
810+ 'user_id': user_id,
811+ 'channel_id': ids[0],
812+ 'start_date': datetime.now().strftime(DF),
813+ 'state': 'join'
814+ }
815+ self.pool.get('im_livechat.channel.session').create(cr, uid, vals, context=context)
816+ return True
817+
818+ def create(self, cr, uid, data, context=None):
819+ channel_id = super(im_livechat_channel, self).create(cr, uid, data, context=context)
820+ channel = self.browse(cr, uid, channel_id, context=context)
821+ for user_id in channel.user_ids:
822+ self._start_channel_session(cr, uid, [channel_id], user_id.id, context=context)
823+ return channel_id
824+
825 def join(self, cr, uid, ids, context=None):
826 self.write(cr, uid, ids, {'user_ids': [(4, uid)]})
827+ self._start_channel_session(cr, uid, ids, uid, context=context)
828 return True
829-
830+
831+ def write(self, cr, uid, ids, vals, context=None):
832+ res = super(im_livechat_channel, self).write(cr, uid, ids, vals, context=context)
833+ im_livechat_session_obj = self.pool.get('im_livechat.channel.session')
834+ for channel in self.browse(cr, uid ,ids, context=context):
835+ for user in channel.user_ids:
836+ records = im_livechat_session_obj.search(cr, uid, [('user_id','=',user.id),('channel_id','=',channel.id)])
837+ if not records:
838+ self._start_channel_session(cr, uid, ids, user.id, context)
839+ return res
840+
841 def quit(self, cr, uid, ids, context=None):
842 self.write(cr, uid, ids, {'user_ids': [(3, uid)]})
843+ history_ids = self.pool.get('im_livechat.channel.session').search(cr, uid, (['user_id','=',uid],['channel_id','in',ids],['state','=','join']))
844+ self.quit_channel_session(cr, uid, history_ids, context=context)
845+ return True
846+
847+ def quit_channel_session(self, cr, uid, ids, context=None):
848+ channel_history_obj = self.pool.get('im_livechat.channel.session')
849+ for history_id in channel_history_obj.browse(cr, uid, ids, context=context):
850+ channel_history_obj.write(cr, uid, history_id.id, {
851+ 'end_date': datetime.now().strftime(DF),
852+ 'state': 'quit'
853+ })
854 return True
855
856 class im_session(osv.osv):
857@@ -213,3 +257,88 @@
858 _columns = {
859 'channel_id': fields.many2one("im_livechat.channel", "Channel"),
860 }
861+
862+class im_hashtag_message(osv.osv):
863+ _inherit = 'im.hashtag.message'
864+
865+ _columns = {
866+ 'channel_id': fields.many2one("im_livechat.channel", "Channel"),
867+ }
868+
869+class im_livechat_channel_session(osv.osv):
870+ _name = 'im_livechat.channel.session'
871+ _rec_name = "channel_name"
872+
873+ def _compute_feedback(self, cr, uid, ids, name, arg, context=None):
874+ result = {}
875+ for chat in self.browse(cr, uid, ids, context=context):
876+ feedback_list = []
877+ reason_list = []
878+ for feedback in chat.feedback_ids:
879+ feedback_list.append(feedback.feedback)
880+ reason_list.append(feedback.reason)
881+ result[chat.id] = [{'feedback_list':feedback_list, 'reason_list':reason_list}]
882+ return result
883+
884+ def _compute_duration(self, cr, uid, ids, name, arg, context=None):
885+ res = {}
886+ for id in self.browse(cr, uid, ids, context=context):
887+ start_date = datetime.strptime(id.start_date, DF)
888+ if id.end_date:
889+ end_date = datetime.strptime(id.end_date, DF)
890+ duration = datetime.strptime(str(end_date - start_date), "%H:%M:%S")
891+ res[id.id] = "%sH %sM" % (duration.hour, duration.minute)
892+ else:
893+ res[id.id] = "0H 0M"
894+ return res
895+
896+ _columns = {
897+ 'user_id': fields.many2one('res.users', 'Support Member'),
898+ 'channel_id': fields.many2one('im_livechat.channel', 'Channel Id', ondelete='cascade'),
899+ 'start_date': fields.datetime('Start Date'),
900+ 'end_date': fields.datetime('End Date'),
901+ 'duration': fields.function(_compute_duration, string='Duration', type='char'),
902+ 'channel_name': fields.related('channel_id', 'name', type='char', string='Channel Name'),
903+ 'responsible_name': fields.related('user_id', 'name', type='char', string='Responsible Name'),
904+ 'feedback_ids': fields.one2many('im.feedback', 'feedback_id', 'Feedback Ids', ondelete='cascade'),
905+ 'feedbacks': fields.function(_compute_feedback, 'Feedbacks', type="serialized", relation='im.feedback'),
906+ 'state': fields.selection([('join','Join'),('quit','Quit')], 'Status', help='Status of user')
907+ }
908+
909+class im_feedback(osv.osv):
910+ _name = "im.feedback"
911+
912+ _rec_name = "feedback"
913+ _columns = {
914+ 'session_id': fields.many2one("im.session", string="Session", ondelete='cascade'),
915+ 'feedback': fields.selection([('10','Good'),('5','Ok'),('1','Bad')], 'Feedback', help='Feedback from user'),
916+ 'reason': fields.text('Reason'),
917+ 'feedback_date': fields.datetime('Date'),
918+ 'feedback_id': fields.many2one('im_livechat.channel.session', 'Feedback id', ondelete='cascade'),
919+ }
920+
921+ def action_chat_history(self, cr, uid, ids, context=None):
922+ session_id = self.browse(cr, uid, ids,context=context)[0].session_id.id
923+
924+ mod_obj = self.pool.get('ir.model.data')
925+ act_obj = self.pool.get('ir.actions.act_window')
926+
927+ action_res = mod_obj.get_object_reference(cr, uid, 'im_livechat', 'action_history')
928+ action_id = action_res and action_res[1] or False
929+ action_res = act_obj.read(cr, uid, [action_id], context=context)[0]
930+ action_res['target'] = 'new'
931+ action_res['domain'] = "[('session_id', 'in', %s)]" % [session_id]
932+ return action_res
933+
934+ def save_feedback(self, cr, uid, data, context=None):
935+ im_session = self.pool.get('im.session').browse(cr, uid, data['session_id'], context=context)
936+ channel_session_obj = self.pool.get('im_livechat.channel.session')
937+ im_user_obj = self.pool.get('im.user')
938+ for user_id in im_session.user_ids:
939+ im_user_id = im_user_obj.browse(cr, uid, user_id.id, context=context)
940+ if im_user_id.user_id:
941+ channel_session_id = channel_session_obj.search(cr, uid, [('channel_id', '=', im_session.channel_id.id),('user_id', '=', im_user_id.user_id.id),('state', '=', 'join')])
942+ data['feedback_id'] = channel_session_id[0]
943+ data['feedback_date'] = datetime.now().strftime(DF)
944+ feedback_id = self.create(cr, openerp.SUPERUSER_ID, data, context=context)
945+ return feedback_id
946
947=== modified file 'im_livechat/im_livechat_demo.xml'
948--- im_livechat/im_livechat_demo.xml 2013-03-15 11:21:53 +0000
949+++ im_livechat/im_livechat_demo.xml 2014-01-15 16:16:23 +0000
950@@ -10,6 +10,50 @@
951 <record id="group_im_livechat" model="res.groups">
952 <field name="users" eval="[(4, ref('base.user_demo'))]"/>
953 </record>
954+
955+ <!-- Resource: im.hashtag.message -->
956+
957+ <record id="im_hashtags_1" model="im.hashtag.message">
958+ <field name="hashtag">#gm</field>
959+ <field name="note">good morning</field>
960+ <field name="user_id"/>
961+ <field name="channel_id" ref="im_livechat.channel_website"/>
962+ </record>
963+
964+ <record id="im_hashtags_2" model="im.hashtag.message">
965+ <field name="hashtag">#gn</field>
966+ <field name="note">good night</field>
967+ <field name="user_id"/>
968+ <field name="channel_id" ref="im_livechat.channel_website"/>
969+ </record>
970+
971+ <record id="im_hashtags_3" model="im.hashtag.message">
972+ <field name="hashtag">#u</field>
973+ <field name="note">you</field>
974+ <field name="user_id"/>
975+ <field name="channel_id" ref="im_livechat.channel_website"/>
976+ </record>
977+
978+ <record id="im_hashtags_4" model="im.hashtag.message">
979+ <field name="hashtag">#ur</field>
980+ <field name="note">your</field>
981+ <field name="user_id"/>
982+ <field name="channel_id" ref="im_livechat.channel_website"/>
983+ </record>
984+
985+ <record id="im_hashtags_5" model="im.hashtag.message">
986+ <field name="hashtag">#abt</field>
987+ <field name="note">about</field>
988+ <field name="user_id"/>
989+ <field name="channel_id" ref="im_livechat.channel_website"/>
990+ </record>
991+
992+ <record id="im_hashtags_6" model="im.hashtag.message">
993+ <field name="hashtag">#bt</field>
994+ <field name="note">but</field>
995+ <field name="user_id"/>
996+ <field name="channel_id" ref="im_livechat.channel_website"/>
997+ </record>
998
999 </data>
1000 </openerp>
1001
1002=== modified file 'im_livechat/im_livechat_view.xml'
1003--- im_livechat/im_livechat_view.xml 2013-09-02 13:56:01 +0000
1004+++ im_livechat/im_livechat_view.xml 2014-01-15 16:16:23 +0000
1005@@ -3,6 +3,176 @@
1006 <data>
1007 <menuitem id="im_livechat" name="Live Chat" parent="mail.mail_feeds_main" groups="group_im_livechat"/>
1008
1009+ <record model="ir.ui.view" id="view_im_livechat_channel_session_search">
1010+ <field name="name">im_livechat.channel.session.search</field>
1011+ <field name="model">im_livechat.channel.session</field>
1012+ <field name="arch" type="xml">
1013+ <search string="Feedback">
1014+ <field name="channel_id"/>
1015+ <field name="responsible_name" string="Responsible"/>
1016+ <field name="channel_name" string="Channel"/>
1017+ <group expand="0" string="Group By...">
1018+ <filter string="Responsible" name="group_user_id" context="{'group_by':'user_id'}"/>
1019+ <filter string="Channel" name="group_channel_id" context="{'group_by':'channel_id'}"/>
1020+ </group>
1021+ </search>
1022+ </field>
1023+ </record>
1024+
1025+ <record model="ir.ui.view" id="view_im_livechat_channel_session_kanban">
1026+ <field name="name">im_livechat.channel.session.kanban</field>
1027+ <field name="model">im_livechat.channel.session</field>
1028+ <field name="arch" type="xml">
1029+ <kanban version="7.0" class="oe_background_grey" create="false">
1030+ <field name="channel_name"/>
1031+ <field name="responsible_name"/>
1032+ <field name="start_date"/>
1033+ <field name="duration"/>
1034+ <field name="user_id"/>
1035+ <templates>
1036+ <t t-name="kanban-box">
1037+ <div t-attf-class="oe_kanban_card oe_kanban_im_livechat oe_kanban_global_click">
1038+ <div class="oe_kanban_content">
1039+ <span>
1040+ <h3 class="oe_kanban_ellipsis"><field name="responsible_name"/></h3>
1041+ <h4 class="oe_kanban_ellipsis"><field name="channel_name"/></h4>
1042+ <div class="oe_kanban_im_livechat_avatars oe_right">
1043+ <img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-if="record.user_id.value" t-att-data-member_id="record.user_id.raw_value"/>
1044+ </div>
1045+ </span>
1046+ <span t-if="record.start_date.raw_value">
1047+ <t t-esc="record.start_date.raw_value.format('m/d/Y')"/>
1048+ </span><br/><br/>
1049+ <span>
1050+ <img src="/im_livechat/static/src/img/groupdefault.png" height="24" width="24" />
1051+ <field name="feedback_ids" invisible="1"/>
1052+ <t t-esc="record.feedback_ids.raw_value.length"/> during <t t-esc="record.duration.raw_value"/>
1053+ </span>
1054+ <div class="oe_kanban_feedback">
1055+ <field name="feedbacks" invisible="1"/>
1056+ <t t-foreach="record.feedbacks.raw_value" t-as="feedbacks">
1057+ <t t-foreach="feedbacks.feedback_list.length" t-as="index">
1058+ <span t-if="feedbacks.feedback_list[index] == 1">
1059+ <img t-att-title="feedbacks.reason_list[index] ? feedbacks.reason_list[index] : 'No Reason'" src="/im/static/src/img/bad.png"></img>
1060+ </span>
1061+ <span t-if="feedbacks.feedback_list[index] == 5">
1062+ <img t-att-title="feedbacks.reason_list[index] ? feedbacks.reason_list[index] : 'No Reason'" src="/im/static/src/img/ok.png"></img>
1063+ </span>
1064+ <span t-if="feedbacks.feedback_list[index] == 10">
1065+ <img title="Good" src="/im/static/src/img/good.png"/>
1066+ </span>
1067+ </t>
1068+ </t>
1069+ </div>
1070+ </div>
1071+ </div>
1072+ </t>
1073+ </templates>
1074+ </kanban>
1075+ </field>
1076+ </record>
1077+
1078+ <record model="ir.ui.view" id="view_im_livechat_channel_session_tree">
1079+ <field name="name">im_livechat.channel.session.tree</field>
1080+ <field name="model">im_livechat.channel.session</field>
1081+ <field name="arch" type="xml">
1082+ <tree string="Feedback" create="false">
1083+ <field name="channel_id" invisible="1"/>
1084+ <field name="user_id" invisible="1"/>
1085+ <field name="channel_name"/>
1086+ <field name="responsible_name"/>
1087+ <field name="start_date"/>
1088+ <field name="duration"/>
1089+ </tree>
1090+ </field>
1091+ </record>
1092+
1093+ <record model="ir.ui.view" id="view_im_message_search">
1094+ <field name="name">im.message.search</field>
1095+ <field name="model">im.message</field>
1096+ <field name="arch" type="xml">
1097+ <search string="Chat History">
1098+ <field name="session_id"/>
1099+ <field name="date" string="Date"/>
1100+ <field name="from_id" string="From"/>
1101+ <group expand="0" string="Group By...">
1102+ <filter string="Session" name="group_session_id" context="{'group_by':'session_id'}"/>
1103+ <filter string="Date" name="group_date" context="{'group_by':'date'}"/>
1104+ </group>
1105+ </search>
1106+ </field>
1107+ </record>
1108+
1109+ <record model="ir.actions.act_window" id="action_history">
1110+ <field name="name">History</field>
1111+ <field name="res_model">im.message</field>
1112+ <field name="view_mode">list</field>
1113+ <field name="domain">[('session_id.channel_id', '!=', None)]</field>
1114+ <field name="search_view_id" ref="view_im_message_search"/>
1115+ </record>
1116+
1117+ <menuitem name="History" parent="im_livechat" id="history" action="action_history" groups="group_im_livechat_manager"/>
1118+
1119+ <record id="im_message_form" model="ir.ui.view">
1120+ <field name="name">im.message.tree</field>
1121+ <field name="model">im.message</field>
1122+ <field name="arch" type="xml">
1123+ <tree string="History">
1124+ <field name="session_id"/>
1125+ <field name="date"/>
1126+ <field name="from_id"/>
1127+ <field name="message"/>
1128+ </tree>
1129+ </field>
1130+ </record>
1131+
1132+ <record model="ir.ui.view" id="view_im_livechat_channel_session_form">
1133+ <field name="name">im_livechat.channel.session.form</field>
1134+ <field name="model">im_livechat.channel.session</field>
1135+ <field name="arch" type="xml">
1136+ <form string="Feedback" version="7.0" create="false" edit="false">
1137+ <group col="4">
1138+ <field name="channel_name" required="1"/>
1139+ <field name="responsible_name"/>
1140+ <field name="start_date"/>
1141+ <field name="duration"/>
1142+ </group>
1143+ <field name="feedback_ids" nolable="1">
1144+ <tree string="List">
1145+ <field name="feedback_date"/>
1146+ <field name="feedback"/>
1147+ <field name="reason"/>
1148+ <button string="Chat History"
1149+ name="action_chat_history"
1150+ icon="terp-project"
1151+ type="object"/>
1152+ </tree>
1153+ </field>
1154+ </form>
1155+ </field>
1156+ </record>
1157+
1158+ <record model="ir.actions.act_window" id="action_im_livechat_channel_session2">
1159+ <field name="name">Feedback</field>
1160+ <field name="res_model">im_livechat.channel.session</field>
1161+ <field name="view_mode">kanban,tree,form</field>
1162+ <field name="context">{
1163+ 'search_default_channel_id': [active_id],
1164+ 'default_channel_id': active_id,
1165+ 'active_test': False,
1166+ }</field>
1167+ <field name="search_view_id" ref="view_im_livechat_channel_session_search"/>
1168+ </record>
1169+
1170+ <record model="ir.actions.act_window" id="action_im_livechat_channel_session">
1171+ <field name="name">Feedback</field>
1172+ <field name="res_model">im_livechat.channel.session</field>
1173+ <field name="view_mode">kanban,tree,form</field>
1174+ <field name="search_view_id" ref="view_im_livechat_channel_session_search"/>
1175+ </record>
1176+
1177+ <menuitem name="Feedback" parent="im_livechat" id="im_feedback" action="action_im_livechat_channel_session" groups="group_im_livechat_manager"/>
1178+
1179 <record model="ir.actions.act_window" id="action_support_channels">
1180 <field name="name">Live Chat Channels</field>
1181 <field name="res_model">im_livechat.channel</field>
1182@@ -20,8 +190,8 @@
1183 </p>
1184 </field>
1185 </record>
1186- <menuitem name="Channels" parent="im_livechat" id="support_channels" action="action_support_channels" groups="group_im_livechat"/>
1187
1188+ <menuitem name="Channels" sequence="5" parent="im_livechat" id="support_channels" action="action_support_channels" groups="group_im_livechat"/>
1189
1190 <record model="ir.ui.view" id="support_channel_kanban">
1191 <field name="name">support_channel.kanban</field>
1192@@ -32,13 +202,19 @@
1193 <field name="web_page"/>
1194 <field name="are_you_inside"/>
1195 <field name="user_ids"/>
1196+ <field name="channel_ids"/>
1197 <templates>
1198 <t t-name="kanban-box">
1199 <div class="oe_group_image">
1200 <a type="open"><img t-att-src="kanban_image('im_livechat.channel', 'image_medium', record.id.value)" class="oe_group_photo"/></a>
1201 </div>
1202 <div class="oe_group_details">
1203- <h4><a type="open"><field name="name"/></a></h4>
1204+ <div class="oe_channel_name">
1205+ <a type="open"><field name="name"/></a>
1206+ </div>
1207+ <div class="oe_channel_feedback" groups="im_livechat.group_im_livechat_manager">
1208+ <a t-if="record.channel_ids.raw_value" name="%(action_im_livechat_channel_session2)d" type="action">Feedback</a>
1209+ </div>
1210 <div class="oe_kanban_footer_left">
1211 <span>
1212 <span class="oe_e">+</span> <t t-esc="(record.user_ids.raw_value || []).length"/>
1213@@ -103,43 +279,35 @@
1214 </group>
1215 </group>
1216
1217- <div attrs='{"invisible": [["web_page", "=", False]]}'>
1218- <separator string="How to use the Live Chat widget?"/>
1219- <p>
1220- Copy and paste this code into your website, within the &amp;lt;head&amp;gt; tag:
1221- </p>
1222- <field name="script" readonly="1" class="oe_tag"/>
1223- <p>
1224- or copy this url and send it by email to your customers or suppliers:
1225- </p>
1226- <field name="web_page" readonly="1" class="oe_tag"/>
1227- </div>
1228-
1229+ <notebook>
1230+ <page string="General">
1231+ <div attrs='{"invisible": [["web_page", "=", False]]}'>
1232+ <separator string="How to use the Live Chat widget?"/>
1233+ <p>
1234+ Copy and paste this code into your website, within the &amp;lt;head&amp;gt; tag:
1235+ </p>
1236+ <field name="script" readonly="1" class="oe_tag"/>
1237+ <p>
1238+ or copy this url and send it by email to your customers or suppliers:
1239+ </p>
1240+ <field name="web_page" readonly="1" class="oe_tag"/>
1241+ </div>
1242+ </page>
1243+ <page string="Answer Shortcut">
1244+ <p class="oe_grey">Enter # to access shortcuts into the chat session.</p>
1245+ <field name="hashtag_channel_ids" nolable="1">
1246+ <tree string="List" editable="top">
1247+ <field name="hashtag"/>
1248+ <field name="note" widget="char"/>
1249+ <field name="user_id"/>
1250+ </tree>
1251+ </field>
1252+ </page>
1253+ </notebook>
1254 </sheet>
1255 </form>
1256 </field>
1257 </record>
1258
1259- <record model="ir.actions.act_window" id="action_history">
1260- <field name="name">History</field>
1261- <field name="res_model">im.message</field>
1262- <field name="view_mode">list</field>
1263- <field name="domain">[('session_id.channel_id', '!=', None)]</field>
1264- </record>
1265- <menuitem name="History" parent="im_livechat" id="history" action="action_history" groups="group_im_livechat_manager"/>
1266-
1267- <record id="im_message_form" model="ir.ui.view">
1268- <field name="name">im.message.tree</field>
1269- <field name="model">im.message</field>
1270- <field name="arch" type="xml">
1271- <tree string="History">
1272- <field name="session_id"/>
1273- <field name="date"/>
1274- <field name="from_id"/>
1275- <field name="message"/>
1276- </tree>
1277- </field>
1278- </record>
1279-
1280 </data>
1281 </openerp>
1282
1283=== modified file 'im_livechat/security/ir.model.access.csv'
1284--- im_livechat/security/ir.model.access.csv 2013-05-24 13:33:41 +0000
1285+++ im_livechat/security/ir.model.access.csv 2014-01-15 16:16:23 +0000
1286@@ -2,7 +2,15 @@
1287 access_ls_chann1,im_livechat.channel,model_im_livechat_channel,,1,0,0,0
1288 access_ls_chann2,im_livechat.channel,model_im_livechat_channel,group_im_livechat,1,1,1,0
1289 access_ls_chann3,im_livechat.channel,model_im_livechat_channel,group_im_livechat_manager,1,1,1,1
1290+access_im_feedback,im.feedback,model_im_feedback,group_im_livechat,1,1,1,0
1291+access_im_feedback_manager,im.feedback,model_im_feedback,group_im_livechat_manager,1,1,1,0
1292+access_im_feedback_anonymous,im.feedback,model_im_feedback,portal.group_anonymous,1,1,0,0
1293+access_ls_channel_session_anonymous,im_livechat.channel.session,model_im_livechat_channel_session,portal.group_anonymous,1,0,0,0
1294+access_ls_channel_session,im_livechat.channel.session,model_im_livechat_channel_session,group_im_livechat,1,1,1,0
1295+access_ls_channel_session_manager,im_livechat.channel.session,model_im_livechat_channel_session,group_im_livechat_manager,1,0,0,1
1296 access_ls_message_portal,im_livechat.im.message.portal,im.model_im_message,portal.group_portal,0,0,0,0
1297 access_im_user_portal,im_livechat.im.user.portal,im.model_im_user,portal.group_portal,1,0,0,0
1298+access_im_message_manager,im_livechat.im.message,im.model_im_message,group_im_livechat_manager,1,1,1,0
1299 access_ls_message,im_livechat.im.message,im.model_im_message,portal.group_anonymous,0,0,0,0
1300+access_ls_message_user,im_livechat.im.message,im.model_im_message,group_im_livechat,1,1,0,0
1301 access_im_user,im_livechat.im.user,im.model_im_user,portal.group_anonymous,1,0,0,0
1302\ No newline at end of file
1303
1304=== added directory 'im_livechat/static/ext/static/css'
1305=== added file 'im_livechat/static/ext/static/css/im_livechat.css'
1306--- im_livechat/static/ext/static/css/im_livechat.css 1970-01-01 00:00:00 +0000
1307+++ im_livechat/static/ext/static/css/im_livechat.css 2014-01-15 16:16:23 +0000
1308@@ -0,0 +1,39 @@
1309+.oe_kanban_im_livechat {
1310+ max-width: 180px;
1311+}
1312+.oe_kanban_im_livechat_avatars img {
1313+ height: 50px;
1314+ width: 50px;
1315+ padding-left: 0px;
1316+ margin-left: 40px;
1317+ margin-top: -50px;
1318+ -moz-border-radius: 2px;
1319+ -webkit-border-radius: 2px;
1320+ border-radius: 2px;
1321+ -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1322+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1323+ -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1324+}
1325+.oe_kanban_feedback {
1326+ padding-top: 8px;
1327+}
1328+.oe_kanban_feedback img{
1329+ width: 30px;
1330+ height: 30px;
1331+}
1332+.oe_channel_feedback > a:hover {
1333+ text-decoration: underline !important;
1334+}
1335+.oe_channel_name {
1336+ font-weight: bold;
1337+}
1338+.oe_kanban_content span > h3,h4 {
1339+ width: 122px;
1340+}
1341+.oe_kanban_record .oe_group_button {
1342+ position: relative;
1343+}
1344+.openerp .oe_kanban_view .oe_kanban_action_button {
1345+ margin-top: 10px;
1346+}
1347+
1348
1349=== modified file 'im_livechat/static/ext/static/js/livesupport.js'
1350--- im_livechat/static/ext/static/js/livesupport.js 2013-09-02 16:15:17 +0000
1351+++ im_livechat/static/ext/static/js/livesupport.js 2014-01-15 16:16:23 +0000
1352@@ -71,7 +71,7 @@
1353 init: function(parent, channel, options) {
1354 this._super(parent);
1355 this.channel = channel;
1356- this.options = options;
1357+ this.options = _.defaults(options,{feedback: true});
1358 this.text = options.buttonText;
1359 },
1360 start: function() {
1361
1362=== added file 'im_livechat/static/src/img/groupdefault.png'
1363Binary files im_livechat/static/src/img/groupdefault.png 1970-01-01 00:00:00 +0000 and im_livechat/static/src/img/groupdefault.png 2014-01-15 16:16:23 +0000 differ
1364=== added directory 'im_livechat/test'
1365=== added file 'im_livechat/test/test_im_livechat.yml'
1366--- im_livechat/test/test_im_livechat.yml 1970-01-01 00:00:00 +0000
1367+++ im_livechat/test/test_im_livechat.yml 2014-01-15 16:16:23 +0000
1368@@ -0,0 +1,39 @@
1369+-
1370+ Create a channel.
1371+-
1372+ !record {model: im_livechat.channel, id: channel_website, view: False}:
1373+ name: YourWebsite.com
1374+ default_message: Hello, how may I help you?
1375+-
1376+ Create a hashtag message without user.
1377+-
1378+ !record {model: im.hashtag.message, id: im_hashtags_7, view: False}:
1379+ hashtag: '#der'
1380+ note: there
1381+ user_id: False
1382+ channel_id: channel_website
1383+-
1384+ Create a hashtag message with user.
1385+-
1386+ !record {model: im.hashtag.message, id: im_hashtags_8, view: False}:
1387+ hashtag: '#dis'
1388+ note: this
1389+ user_id: base.partner_root
1390+ channel_id: channel_website
1391+-
1392+ I check that the hashtag message is created successfully.
1393+-
1394+ !python {model: im.hashtag.message}: |
1395+ hashtag_id = self.browse(cr, uid, ref('im_hashtags_7'), context={})
1396+ assert hashtag_id, 'No Hashtag is generated!'
1397+-
1398+ Create an im user.
1399+-
1400+ !record {model: im.user, id: im_user_1, view: False}:
1401+ user_id: base.partner_root
1402+-
1403+ I browse individual user assigned and global hashtag message.
1404+-
1405+ !python {model: im.hashtag.message}: |
1406+ hashtag_ids = self.pool.get('im.user').get_hashtags(cr, uid, ref('im_user_1'), context={})
1407+ assert hashtag_ids, 'No more Hashtags!'
1408
1409=== modified file 'im_livechat/web_page.html'
1410--- im_livechat/web_page.html 2013-03-15 11:21:53 +0000
1411+++ im_livechat/web_page.html 2014-01-15 16:16:23 +0000
1412@@ -41,7 +41,6 @@
1413 margin-top: -150px;
1414 color: white;
1415 text-shadow: 0 1px 0 rgba(34, 52, 72, 0.2);
1416- z-index: 10;
1417 text-align: center;
1418 }
1419 .main h1 {

Subscribers

People subscribed via source and target branches

to all changes: