Merge lp:~openerp-dev/openobject-addons/trunk-chat-feature into lp:openobject-addons
- trunk-chat-feature
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+185263@code.launchpad.net |
Commit message
Description of the change
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' |
282 | Binary 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' |
284 | Binary 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' |
286 | Binary 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' |
288 | Binary 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 &lt;head&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 &lt;head&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' |
1363 | Binary 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 { |