[MIG] im_chat, im_livechat : re structure the modules files.

Create models/ and controllers/ directories, and split the Python and XML files to fit coding guidelines, and prepare migration.
This commit is contained in:
Jérome Maes
2015-04-28 17:04:16 +02:00
parent 0280a5f390
commit 7096fee53c
35 changed files with 419 additions and 340 deletions
+3 -1
View File
@@ -1 +1,3 @@
import bus
# -*- coding: utf-8 -*-
import models
import controllers
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
import main
+36
View File
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
import openerp
from openerp.http import request
from openerp.addons.bus.models.bus import dispatch
class BusController(openerp.http.Controller):
""" Examples:
openerp.jsonRpc('/longpolling/poll','call',{"channels":["c1"],last:0}).then(function(r){console.log(r)});
openerp.jsonRpc('/longpolling/send','call',{"channel":"c1","message":"m1"});
openerp.jsonRpc('/longpolling/send','call',{"channel":"c2","message":"m2"});
"""
@openerp.http.route('/longpolling/send', type="json", auth="public")
def send(self, channel, message):
if not isinstance(channel, basestring):
raise Exception("bus.Bus only string channels are allowed.")
registry, cr, uid = request.registry, request.cr, request.session.uid
return registry['bus.bus'].sendone(cr, uid, channel, message)
# override to add channels
def _poll(self, dbname, channels, last, options):
request.cr.close()
request._cr = None
return dispatch.poll(dbname, channels, last)
@openerp.http.route('/longpolling/poll', type="json", auth="public")
def poll(self, channels, last, options=None):
if options is None:
options = {}
if not dispatch:
raise Exception("bus.Bus unavailable")
if [c for c in channels if not isinstance(c, basestring)]:
raise Exception("bus.Bus only string channels are allowed.")
return self._poll(request.db, channels, last, options)
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
import bus
@@ -156,37 +156,3 @@ class ImDispatch(object):
return self
dispatch = ImDispatch().start()
#----------------------------------------------------------
# Controller
#----------------------------------------------------------
class Controller(openerp.http.Controller):
""" Examples:
openerp.jsonRpc('/longpolling/poll','call',{"channels":["c1"],last:0}).then(function(r){console.log(r)});
openerp.jsonRpc('/longpolling/send','call',{"channel":"c1","message":"m1"});
openerp.jsonRpc('/longpolling/send','call',{"channel":"c2","message":"m2"});
"""
@openerp.http.route('/longpolling/send', type="json", auth="public")
def send(self, channel, message):
if not isinstance(channel, basestring):
raise Exception("bus.Bus only string channels are allowed.")
registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
return registry['bus.bus'].sendone(cr, uid, channel, message)
# override to add channels
def _poll(self, dbname, channels, last, options):
request.cr.close()
request._cr = None
return dispatch.poll(dbname, channels, last)
@openerp.http.route('/longpolling/poll', type="json", auth="public")
def poll(self, channels, last, options=None):
if options is None:
options = {}
if not dispatch:
raise Exception("bus.Bus unavailable")
if [c for c in channels if not isinstance(c, basestring)]:
print channels
raise Exception("bus.Bus only string channels are allowed.")
return self._poll(request.db, channels, last, options)
+3 -1
View File
@@ -1 +1,3 @@
import im_chat
# -*- coding: utf-8 -*-
import models
import controllers
+9 -9
View File
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
{
'name' : 'Instant Messaging',
'version': '1.0',
'summary': 'OpenERP Chat',
'author': 'OpenERP SA',
'summary': 'Chat between users',
'author': 'Odoo SA',
'sequence': '18',
'category': 'Tools',
'complexity': 'easy',
@@ -11,18 +12,17 @@
"""
Instant Messaging
=================
Allows users to chat with each other in real time. Find other users easily and
chat in real time. It support several chats in parallel.
""",
'data': [
'security/ir.model.access.csv',
'security/im_security.xml',
'views/im_chat.xml',
'views/im_chat_view.xml',
'im_chat_data.xml',
],
'depends' : ['base', 'web', 'bus'],
'security/im_chat_session_security.xml',
'views/im_chat_session_templates.xml',
'views/im_chat_session_views.xml',
'data/im_chat_session_data.xml',
],
'depends': ['base', 'web', 'bus'],
'qweb': ['static/src/xml/*.xml'],
'application': True,
'installable': True,
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*
import main
+53
View File
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*
import base64
import openerp
import simplejson
from openerp import SUPERUSER_ID
from openerp.http import request
#----------------------------------------------------------
# Controllers
#----------------------------------------------------------
class Controller(openerp.addons.bus.controllers.main.BusController):
def _poll(self, dbname, channels, last, options):
if request.session.uid:
registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
registry.get('im_chat.presence').update(cr, uid, options.get('im_presence', False), context=context)
## For performance issue, the real time status notification is disabled. This means a change of status are still braoadcasted
## but not received by anyone. Otherwise, all listening user restart their longpolling at the same time and cause a 'ConnectionPool Full Error'
## since there is not enought cursors for everyone. Now, when a user open his list of users, an RPC call is made to update his user status list.
##channels.append((request.db,'im_chat.presence'))
# channel to receive message
channels.append((request.db,'im_chat.session', request.uid))
return super(Controller, self)._poll(dbname, channels, last, options)
@openerp.http.route('/im_chat/init', type="json", auth="none")
def init(self):
registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
notifications = registry['im_chat.message'].init_messages(cr, uid, context=context)
return notifications
@openerp.http.route('/im_chat/post', type="json", auth="none")
def post(self, uuid, message_type, message_content):
registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
# execute the post method as SUPERUSER_ID
message_id = registry["im_chat.message"].post(cr, openerp.SUPERUSER_ID, uid, uuid, message_type, message_content, context=context)
return message_id
@openerp.http.route(['/im_chat/image/<string:uuid>/<string:user_id>'], type='http', auth="none")
def image(self, uuid, user_id):
registry, cr, context, uid = request.registry, request.cr, request.context, request.session.uid
# get the image
Session = registry.get("im_chat.session")
image_b64 = Session.get_image(cr, openerp.SUPERUSER_ID, uuid, simplejson.loads(user_id), context)
# built the response
image_data = base64.b64decode(image_b64)
headers = [('Content-Type', 'image/png')]
headers.append(('Content-Length', len(image_data)))
return request.make_response(image_data, headers)
@openerp.http.route(['/im_chat/history'], type="json", auth="none")
def history(self, uuid, last_id=False, limit=20):
registry, cr, uid, context = request.registry, request.cr, request.session.uid or openerp.SUPERUSER_ID, request.context
return registry["im_chat.message"].get_messages(cr, uid, uuid, last_id, limit, context=context)
+3
View File
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
import im_chat_session
import res_users
@@ -6,7 +6,6 @@ import time
import uuid
import random
import re
import simplejson
import openerp
import cgi
@@ -14,7 +13,7 @@ from openerp import tools, _
from openerp.http import request
from openerp.osv import osv, fields
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
from openerp.addons.bus.bus import TIMEOUT
from openerp.addons.bus.models.bus import TIMEOUT
from openerp.exceptions import UserError
_logger = logging.getLogger(__name__)
@@ -394,119 +393,3 @@ class im_chat_presence(osv.Model):
notifications.append([(cr.dbname,'im_chat.presence'), {'id': presence.user_id.id, 'im_status': presence.status}])
self.pool['bus.bus'].sendmany(cr, uid, notifications)
return True
class res_users(osv.Model):
_inherit = "res.users"
def _get_im_status(self, cr, uid, ids, fields, arg, context=None):
""" function computing the im_status field of the users """
r = dict((i, 'offline') for i in ids)
status_ids = self.pool['im_chat.presence'].search(cr, uid, [('user_id', 'in', ids)], context=context)
status = self.pool['im_chat.presence'].browse(cr, uid, status_ids, context=context)
for s in status:
r[s.user_id.id] = s.status
return r
_columns = {
'im_status' : fields.function(_get_im_status, type="char", string="IM Status"),
}
def im_search(self, cr, uid, name, limit=20, context=None):
""" search users with a name and return its id, name and im_status """
result = [];
# find the employee group
group_employee = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base', 'group_user')[1]
where_clause_base = " U.active = 't' "
query_params = ()
if name:
where_clause_base += " AND P.name ILIKE %s "
query_params = query_params + ('%'+name+'%',)
# first query to find online employee
cr.execute('''SELECT U.id as id, P.name as name, COALESCE(S.status, 'offline') as im_status
FROM im_chat_presence S
JOIN res_users U ON S.user_id = U.id
JOIN res_partner P ON P.id = U.partner_id
WHERE '''+where_clause_base+'''
AND U.id != %s
AND EXISTS (SELECT 1 FROM res_groups_users_rel G WHERE G.gid = %s AND G.uid = U.id)
AND S.status = 'online'
ORDER BY P.name
LIMIT %s
''', query_params + (uid, group_employee, limit))
result = result + cr.dictfetchall()
# second query to find other online people
if(len(result) < limit):
cr.execute('''SELECT U.id as id, P.name as name, COALESCE(S.status, 'offline') as im_status
FROM im_chat_presence S
JOIN res_users U ON S.user_id = U.id
JOIN res_partner P ON P.id = U.partner_id
WHERE '''+where_clause_base+'''
AND U.id NOT IN %s
AND S.status = 'online'
ORDER BY P.name
LIMIT %s
''', query_params + (tuple([u["id"] for u in result]) + (uid,), limit-len(result)))
result = result + cr.dictfetchall()
# third query to find all other people
if(len(result) < limit):
cr.execute('''SELECT U.id as id, P.name as name, COALESCE(S.status, 'offline') as im_status
FROM res_users U
LEFT JOIN im_chat_presence S ON S.user_id = U.id
LEFT JOIN res_partner P ON P.id = U.partner_id
WHERE '''+where_clause_base+'''
AND U.id NOT IN %s
ORDER BY P.name
LIMIT %s
''', query_params + (tuple([u["id"] for u in result]) + (uid,), limit-len(result)))
result = result + cr.dictfetchall()
return result
#----------------------------------------------------------
# Controllers
#----------------------------------------------------------
class Controller(openerp.addons.bus.bus.Controller):
def _poll(self, dbname, channels, last, options):
if request.session.uid:
registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
registry.get('im_chat.presence').update(cr, uid, options.get('im_presence', False), context=context)
## For performance issue, the real time status notification is disabled. This means a change of status are still braoadcasted
## but not received by anyone. Otherwise, all listening user restart their longpolling at the same time and cause a 'ConnectionPool Full Error'
## since there is not enought cursors for everyone. Now, when a user open his list of users, an RPC call is made to update his user status list.
##channels.append((request.db,'im_chat.presence'))
# channel to receive message
channels.append((request.db,'im_chat.session', request.uid))
return super(Controller, self)._poll(dbname, channels, last, options)
@openerp.http.route('/im_chat/init', type="json", auth="none")
def init(self):
registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
notifications = registry['im_chat.message'].init_messages(cr, uid, context=context)
return notifications
@openerp.http.route('/im_chat/post', type="json", auth="none")
def post(self, uuid, message_type, message_content):
registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
# execute the post method as SUPERUSER_ID
message_id = registry["im_chat.message"].post(cr, openerp.SUPERUSER_ID, uid, uuid, message_type, message_content, context=context)
return message_id
@openerp.http.route(['/im_chat/image/<string:uuid>/<string:user_id>'], type='http', auth="none")
def image(self, uuid, user_id):
registry, cr, context, uid = request.registry, request.cr, request.context, request.session.uid
# get the image
Session = registry.get("im_chat.session")
image_b64 = Session.get_image(cr, openerp.SUPERUSER_ID, uuid, simplejson.loads(user_id), context)
# built the response
image_data = base64.b64decode(image_b64)
headers = [('Content-Type', 'image/png')]
headers.append(('Content-Length', len(image_data)))
return request.make_response(image_data, headers)
@openerp.http.route(['/im_chat/history'], type="json", auth="none")
def history(self, uuid, last_id=False, limit=20):
registry, cr, uid, context = request.registry, request.cr, request.session.uid or openerp.SUPERUSER_ID, request.context
return registry["im_chat.message"].get_messages(cr, uid, uuid, last_id, limit, context=context)
+75
View File
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
from openerp.osv import osv, fields
class res_users(osv.osv):
_inherit = "res.users"
def _get_im_status(self, cr, uid, ids, fields, arg, context=None):
""" function computing the im_status field of the users """
r = dict((i, 'offline') for i in ids)
status_ids = self.pool['im_chat.presence'].search(cr, uid, [('user_id', 'in', ids)], context=context)
status = self.pool['im_chat.presence'].browse(cr, uid, status_ids, context=context)
for s in status:
r[s.user_id.id] = s.status
return r
_columns = {
'im_status' : fields.function(_get_im_status, type="char", string="IM Status"),
}
def im_search(self, cr, uid, name, limit=20, context=None):
""" search users with a name and return its id, name and im_status """
result = [];
# find the employee group
group_employee = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base', 'group_user')[1]
where_clause_base = " U.active = 't' "
query_params = ()
if name:
where_clause_base += " AND P.name ILIKE %s "
query_params = query_params + ('%'+name+'%',)
# first query to find online employee
cr.execute('''SELECT U.id as id, P.name as name, COALESCE(S.status, 'offline') as im_status
FROM im_chat_presence S
JOIN res_users U ON S.user_id = U.id
JOIN res_partner P ON P.id = U.partner_id
WHERE '''+where_clause_base+'''
AND U.id != %s
AND EXISTS (SELECT 1 FROM res_groups_users_rel G WHERE G.gid = %s AND G.uid = U.id)
AND S.status = 'online'
ORDER BY P.name
LIMIT %s
''', query_params + (uid, group_employee, limit))
result = result + cr.dictfetchall()
# second query to find other online people
if(len(result) < limit):
cr.execute('''SELECT U.id as id, P.name as name, COALESCE(S.status, 'offline') as im_status
FROM im_chat_presence S
JOIN res_users U ON S.user_id = U.id
JOIN res_partner P ON P.id = U.partner_id
WHERE '''+where_clause_base+'''
AND U.id NOT IN %s
AND S.status = 'online'
ORDER BY P.name
LIMIT %s
''', query_params + (tuple([u["id"] for u in result]) + (uid,), limit-len(result)))
result = result + cr.dictfetchall()
# third query to find all other people
if(len(result) < limit):
cr.execute('''SELECT U.id as id, P.name as name, COALESCE(S.status, 'offline') as im_status
FROM res_users U
LEFT JOIN im_chat_presence S ON S.user_id = U.id
LEFT JOIN res_partner P ON P.id = U.partner_id
WHERE '''+where_clause_base+'''
AND U.id NOT IN %s
ORDER BY P.name
LIMIT %s
''', query_params + (tuple([u["id"] for u in result]) + (uid,), limit-len(result)))
result = result + cr.dictfetchall()
return result
@@ -4,10 +4,10 @@
<data>
<template id="assets_backend" name="im_chat assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/im_chat/static/src/css/im_common.css"/>
<link rel="stylesheet" href="/im_chat/static/src/css/im_chat.css"/>
<link rel="stylesheet" href="/im_chat/static/src/css/im_chat_common.css"/>
<link rel="stylesheet" href="/im_chat/static/src/css/im_chat_backend.css"/>
<script type="text/javascript" src="/im_chat/static/src/js/im_chat_common.js"></script>
<script type="text/javascript" src="/im_chat/static/src/js/im_chat.js"></script>
<script type="text/javascript" src="/im_chat/static/src/js/im_chat_backend.js"></script>
</xpath>
</template>
</data>
+3 -2
View File
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
import controllers
import im_livechat
import report
import models
import report
+9 -7
View File
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
{
'name' : 'Live Chat',
'author': 'OpenERP SA',
'author': 'Odoo SA',
'version': '1.0',
'summary': 'Live Chat with Visitors/Customers',
'category': 'Tools',
@@ -18,15 +19,16 @@ Help your customers with this chat, and analyse their feedback.
""",
'data': [
"security/im_livechat_security.xml",
"security/im_livechat_channel_security.xml",
"security/ir.model.access.csv",
"views/im_livechat_view.xml",
"views/im_livechat.xml",
"report/im_livechat_report.xml",
"im_livechat_data.xml"
"views/im_chat_session_views.xml",
"views/im_livechat_channel_views.xml",
"views/im_livechat_channel_templates.xml",
"report/im_livechat_report_views.xml",
"data/im_livechat_channel_data.xml"
],
'demo': [
"im_livechat_demo.xml",
"data/im_livechat_channel_demo.xml",
],
'depends' : ["mail", "rating", "im_chat"],
'installable': True,
+1 -2
View File
@@ -1,3 +1,2 @@
# -*- coding: utf-8 -*-
import livechat
import rating
import main
@@ -67,3 +67,35 @@ class LivechatController(http.Controller):
with reg.cursor() as cr:
return len(reg.get('im_livechat.channel').get_available_users(cr, uid, channel)) > 0
@http.route('/rating/livechat/feedback', type='json', auth='none')
def rating_livechat_feedback(self, uuid, rate, reason=None, **kwargs):
Session = request.env['im_chat.session']
Rating = request.env['rating.rating']
session_ids = Session.sudo().search([('uuid', '=', uuid)])
if session_ids:
session = session_ids[0]
# limit the creation : only ONE rating per session
values = {
'rating' : rate,
}
if not session.rating_ids:
values.update({
'res_id' : session.id,
'res_model' : 'im_chat.session',
'rating' : rate,
'feedback' : reason,
})
# find the partner related to the user of the conversation
rated_partner_id = False
if session.user_ids:
rated_partner_id = session.user_ids[0] and session.user_ids[0].partner_id.id or False
values['rated_partner_id'] = rated_partner_id
# create the rating
rating = Rating.sudo().create(values)
else:
if reason:
values['feedback'] = reason
rating = session.rating_ids[0]
rating.write(values)
return rating.id
return False
-40
View File
@@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
import openerp
from openerp.addons.rating.controllers.main import Rating
from openerp.addons.web import http
from openerp.http import request
class LivechatRatingController(Rating):
@http.route('/rating/livechat/feedback', type='json', auth='none')
def rating_livechat_feedback(self, uuid, rate, reason=None, **kwargs):
Session = request.env['im_chat.session']
Rating = request.env['rating.rating']
session_ids = Session.sudo().search([('uuid', '=', uuid)])
if session_ids:
session = session_ids[0]
# limit the creation : only ONE rating per session
values = {
'rating' : rate,
}
if not session.rating_ids:
values.update({
'res_id' : session.id,
'res_model' : 'im_chat.session',
'rating' : rate,
'feedback' : reason,
})
# find the partner related to the user of the conversation
rated_partner_id = False
if session.user_ids:
rated_partner_id = session.user_ids[0] and session.user_ids[0].partner_id.id or False
values['rated_partner_id'] = rated_partner_id
# create the rating
rating = Rating.sudo().create(values)
else:
if reason:
values['feedback'] = reason
rating = session.rating_ids[0]
rating.write(values)
return rating.id
return False
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*
import im_livechat_channel
import im_chat_session
import rating
@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
import openerp
from openerp.osv import osv, fields
class im_chat_session(osv.Model):
_name = 'im_chat.session'
_inherit = ['im_chat.session', 'rating.mixin']
def _get_fullname(self, cr, uid, ids, fields, arg, context=None):
""" built the complete name of the session """
result = {}
sessions = self.browse(cr, uid, ids, context=context)
for session in sessions:
names = []
for user in session.user_ids:
names.append(user.name)
if session.anonymous_name:
names.append(session.anonymous_name)
result[session.id] = ', '.join(names)
return result
_columns = {
'anonymous_name' : fields.char('Anonymous Name'),
'create_date': fields.datetime('Create Date', required=True, select=True),
'channel_id': fields.many2one("im_livechat.channel", "Channel"),
'fullname': fields.function(_get_fullname, type="char", string="Complete name"),
}
def is_in_session(self, cr, uid, uuid, user_id, context=None):
""" return if the given user_id is in the session """
sids = self.search(cr, uid, [('uuid', '=', uuid)], context=context, limit=1)
for session in self.browse(cr, uid, sids, context=context):
if session.anonymous_name and user_id == openerp.SUPERUSER_ID:
return True
else:
return super(im_chat_session, self).is_in_session(cr, uid, uuid, user_id, context=context)
return False
def users_infos(self, cr, uid, ids, context=None):
""" add the anonymous user in the user of the session """
for session in self.browse(cr, uid, ids, context=context):
users_infos = super(im_chat_session, self).users_infos(cr, uid, ids, context=context)
if session.anonymous_name:
users_infos.append({'id' : False, 'name' : session.anonymous_name, 'im_status' : 'online'})
return users_infos
def quit_user(self, cr, uid, uuid, context=None):
""" action of leaving a given session """
sids = self.search(cr, uid, [('uuid', '=', uuid)], context=context, limit=1)
for session in self.browse(cr, openerp.SUPERUSER_ID, sids, context=context):
if session.anonymous_name:
# an identified user can leave an anonymous session if there is still another idenfied user in it
if uid and uid in [u.id for u in session.user_ids] and len(session.user_ids) > 1:
self.remove_user(cr, uid, session.id, context=context)
return True
return False
else:
return super(im_chat_session, self).quit_user(cr, uid, session.id, context=context)
def cron_remove_empty_session(self, cr, uid, context=None):
groups = self.pool['im_chat.message'].read_group(cr, uid, [], ['to_id'], ['to_id'], context=context)
not_empty_session_ids = [group['to_id'][0] for group in groups]
empty_session_ids = self.search(cr, uid, [('id', 'not in', not_empty_session_ids), ('channel_id', '!=', False)], context=context)
self.unlink(cr, uid, empty_session_ids, context=context)
@@ -1,24 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import openerp
import openerp.addons.im_chat.im_chat
import random
+19
View File
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from openerp import api, models
class Rating(models.Model):
_inherit = "rating.rating"
@api.one
@api.depends('res_model', 'res_id')
def _compute_res_name(self):
# cannot change the rec_name of session since it is use to create the bus channel
# so, need to override this method to set the same alternative rec_name as in reporting
if self.res_model == 'im_chat.session':
current_object = self.env[self.res_model].sudo().browse(self.res_id)
self.res_name = ('%s / %s') % (current_object.channel_id.name, current_object.id)
else:
super(Rating, self)._compute_res_name()
@@ -0,0 +1,91 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- History : form, list and search views -->
<record id="action_session_history" model="ir.actions.act_window">
<field name="name">History</field>
<field name="res_model">im_chat.session</field>
<field name="view_type">form</field>
<field name="view_mode">list,form</field>
<field name="domain">[('channel_id', '!=', None)]</field>
<field name="context">{'group_by': ['channel_id', 'create_date:month']}</field>
</record>
<record id="im_chat_session_search" model="ir.ui.view">
<field name="name">im_chat.session.search</field>
<field name="model">im_chat.session</field>
<field name="arch" type="xml">
<search string="Search history">
<filter name="id" string="My sessions" domain="[('user_ids','in', uid)]"/>
<group expand="0" string="Group By...">
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'channel_id'}"/>
<separator orientation="vertical" />
<filter name="group_by_day" string="Creation date (day)" domain="[]" context="{'group_by':'create_date:day'}"/>
<filter name="group_by_week" string="Creation date (week)" domain="[]" context="{'group_by':'create_date:week'}"/>
<filter name="group_by_month" string="Creation date (month)" domain="[]" context="{'group_by':'create_date:month'}" />
<filter name="group_by_year" string="Creation date (year)" domain="[]" context="{'group_by':'create_date:year'}"/>
</group>
</search>
</field>
</record>
<record id="im_chat_session_list_view" model="ir.ui.view">
<field name="name">im_chat.session.tree</field>
<field name="model">im_chat.session</field>
<field name="arch" type="xml">
<tree string="History" create="false">
<field name="id"/>
<field name="fullname"/>
<field name="create_date"/>
</tree>
</field>
</record>
<record id="im_chat_session_form_view" model="ir.ui.view">
<field name="name">im_chat.session.form</field>
<field name="model">im_chat.session</field>
<field name="arch" type="xml">
<form string="Session Form" create="false" edit="false">
<sheet>
<group>
<group string="General">
<field name="id"/>
<field name="fullname" />
<field name="create_date" readonly="1"/>
</group>
<group string="Feedback">
<field name="rating_ids" mode="kanban" nolabel="1">
<kanban>
<field name="rating"/>
<field name="feedback"/>
<field name="res_name"/>
<field name="create_date"/>
<templates>
<t t-name="kanban-box">
<div class="oe_group_details" style="min-height: 40px">
<img t-attf-src="rating/static/src/img/rating_#{record.rating.raw_value and record.rating.raw_value or 0}.png" class="oe_kanban_image" style="float:left; margin-right: 10px;"/>
<span t-if="record.feedback.raw_value">
<t t-esc="record.feedback.raw_value"/>
</span>
</div>
</t>
</templates>
</kanban>
</field>
</group>
</group>
<field name="message_ids" type="tree">
<tree string="History">
<field name="create_date" />
<field name="from_id" />
<field name="message" />
</tree>
</field>
</sheet>
</form>
</field>
</record>
</data>
</openerp>
@@ -139,7 +139,7 @@
<script type="text/javascript" src="/im_chat/static/src/js/im_chat_common.js"></script>
<script type="text/javascript" src="/im_livechat/static/src/js/im_livechat.js"></script>
<!-- CSS -->
<link rel="stylesheet" href="/im_chat/static/src/css/im_common.css"></link>
<link rel="stylesheet" href="/im_chat/static/src/css/im_chat_common.css"></link>
<link rel="stylesheet" href="/im_livechat/static/src/css/im_livechat.css"/>
</template>
@@ -1,108 +1,6 @@
<?xml version="1.0"?>
<openerp>
<data>
<!--
Views for im_chat.session
-->
<!-- History : form, list and search views -->
<record id="action_session_history" model="ir.actions.act_window">
<field name="name">History</field>
<field name="res_model">im_chat.session</field>
<field name="view_type">form</field>
<field name="view_mode">list,form</field>
<field name="domain">[('channel_id', '!=', None)]</field>
<field name="context">{'group_by': ['channel_id', 'create_date:month']}</field>
</record>
<record id="im_chat_session_search" model="ir.ui.view">
<field name="name">im_chat.session.search</field>
<field name="model">im_chat.session</field>
<field name="arch" type="xml">
<search string="Search history">
<filter name="id" string="My sessions" domain="[('user_ids','in', uid)]"/>
<group expand="0" string="Group By...">
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'channel_id'}"/>
<separator orientation="vertical" />
<filter name="group_by_day" string="Creation date (day)" domain="[]" context="{'group_by':'create_date:day'}"/>
<filter name="group_by_week" string="Creation date (week)" domain="[]" context="{'group_by':'create_date:week'}"/>
<filter name="group_by_month" string="Creation date (month)" domain="[]" context="{'group_by':'create_date:month'}" />
<filter name="group_by_year" string="Creation date (year)" domain="[]" context="{'group_by':'create_date:year'}"/>
</group>
</search>
</field>
</record>
<record id="im_chat_session_list_view" model="ir.ui.view">
<field name="name">im_chat.session.tree</field>
<field name="model">im_chat.session</field>
<field name="arch" type="xml">
<tree string="History" create="false">
<field name="id"/>
<field name="fullname"/>
<field name="create_date"/>
</tree>
</field>
</record>
<record id="im_chat_session_form_view" model="ir.ui.view">
<field name="name">im_chat.session.form</field>
<field name="model">im_chat.session</field>
<field name="arch" type="xml">
<form string="Session Form" create="false" edit="false">
<sheet>
<group>
<group string="General">
<field name="id"/>
<field name="fullname" />
<field name="create_date" readonly="1"/>
</group>
<group string="Feedback">
<field name="rating_ids" mode="kanban" nolabel="1">
<kanban>
<field name="rating"/>
<field name="feedback"/>
<field name="res_name"/>
<field name="create_date"/>
<templates>
<t t-name="kanban-box">
<div class="oe_group_details" style="min-height: 40px">
<img t-attf-src="rating/static/src/img/rating_#{record.rating.raw_value and record.rating.raw_value or 0}.png" class="oe_kanban_image" style="float:left; margin-right: 10px;"/>
<span t-if="record.feedback.raw_value">
<t t-esc="record.feedback.raw_value"/>
</span>
</div>
</t>
</templates>
</kanban>
</field>
</group>
</group>
<field name="message_ids" type="tree">
<tree string="History">
<field name="create_date" />
<field name="from_id" />
<field name="message" />
</tree>
</field>
</sheet>
</form>
</field>
</record>
<!-- Session of a channel : list view -->
<record id="action_session_channel" model="ir.actions.act_window">
<field name="name">Sessions</field>
<field name="res_model">im_chat.session</field>
<field name="view_mode">list,form</field>
<field name="domain">[('channel_id','in',[active_id])]</field>
<field name="context">{
'search_default_channel_id': [active_id],
'default_channel_id': active_id,
}</field>
<field name="search_view_id" ref="im_chat_session_search"/>
</record>
<!--
Views for im_livechat.channel