[MERGE] forward port of branch saas-3 up to 3d4b82c
[odoo/odoo.git] / addons / im_livechat / im_livechat.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 import random
23 import openerp
24 import json
25 import openerp.addons.im_chat.im_chat
26
27 from openerp.osv import osv, fields
28 from openerp import tools
29 from openerp import http
30 from openerp.http import request
31
32 class im_livechat_channel(osv.Model):
33     _name = 'im_livechat.channel'
34
35     def _get_default_image(self, cr, uid, context=None):
36         image_path = openerp.modules.get_module_resource('im_livechat', 'static/src/img', 'default.png')
37         return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
38     def _get_image(self, cr, uid, ids, name, args, context=None):
39         result = dict.fromkeys(ids, False)
40         for obj in self.browse(cr, uid, ids, context=context):
41             result[obj.id] = tools.image_get_resized_images(obj.image)
42         return result
43     def _set_image(self, cr, uid, id, name, value, args, context=None):
44         return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
45
46     def _are_you_inside(self, cr, uid, ids, name, arg, context=None):
47         res = {}
48         for record in self.browse(cr, uid, ids, context=context):
49             res[record.id] = False
50             for user in record.user_ids:
51                 if user.id == uid:
52                     res[record.id] = True
53                     break
54         return res
55
56     def _script_external(self, cr, uid, ids, name, arg, context=None):
57         values = {
58             "url": self.pool.get('ir.config_parameter').get_param(cr, openerp.SUPERUSER_ID, 'web.base.url'),
59             "dbname":cr.dbname
60         }
61         res = {}
62         for record in self.browse(cr, uid, ids, context=context):
63             values["channel"] = record.id
64             res[record.id] = self.pool['ir.ui.view'].render(cr, uid, 'im_livechat.external_loader', values, context=context)
65         return res
66
67     def _script_internal(self, cr, uid, ids, name, arg, context=None):
68         values = {
69             "url": self.pool.get('ir.config_parameter').get_param(cr, openerp.SUPERUSER_ID 'web.base.url'),
70             "dbname":cr.dbname
71         }
72         res = {}
73         for record in self.browse(cr, uid, ids, context=context):
74             values["channel"] = record.id
75             res[record.id] = self.pool['ir.ui.view'].render(cr, uid, 'im_livechat.internal_loader', values, context=context)
76         return res
77
78     def _web_page(self, cr, uid, ids, name, arg, context=None):
79         res = {}
80         for record in self.browse(cr, uid, ids, context=context):
81             res[record.id] = self.pool.get('ir.config_parameter').get_param(cr, openerp.SUPERUSER_ID, 'web.base.url') + \
82                 "/im_livechat/support/%s/%i" % (cr.dbname, record.id)
83         return res
84
85     _columns = {
86         'name': fields.char(string="Channel Name", size=200, required=True),
87         'user_ids': fields.many2many('res.users', 'im_livechat_channel_im_user', 'channel_id', 'user_id', string="Users"),
88         'are_you_inside': fields.function(_are_you_inside, type='boolean', string='Are you inside the matrix?', store=False),
89         'script_internal': fields.function(_script_internal, type='text', string='Script (internal)', store=False),
90         'script_external': fields.function(_script_external, type='text', string='Script (external)', store=False),
91         'web_page': fields.function(_web_page, type='char', string='Web Page', store=False),
92         'button_text': fields.char(string="Text of the Button"),
93         'input_placeholder': fields.char(string="Chat Input Placeholder"),
94         'default_message': fields.char(string="Welcome Message", help="This is an automated 'welcome' message that your visitor will see when they initiate a new chat session."),
95         # image: all image fields are base64 encoded and PIL-supported
96         'image': fields.binary("Photo",
97             help="This field holds the image used as photo for the group, limited to 1024x1024px."),
98         'image_medium': fields.function(_get_image, fnct_inv=_set_image,
99             string="Medium-sized photo", type="binary", multi="_get_image",
100             store={
101                 'im_livechat.channel': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
102             },
103             help="Medium-sized photo of the group. It is automatically "\
104                  "resized as a 128x128px image, with aspect ratio preserved. "\
105                  "Use this field in form views or some kanban views."),
106         'image_small': fields.function(_get_image, fnct_inv=_set_image,
107             string="Small-sized photo", type="binary", multi="_get_image",
108             store={
109                 'im_livechat.channel': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
110             },
111             help="Small-sized photo of the group. It is automatically "\
112                  "resized as a 64x64px image, with aspect ratio preserved. "\
113                  "Use this field anywhere a small image is required."),
114     }
115
116     def _default_user_ids(self, cr, uid, context=None):
117         return [(6, 0, [uid])]
118
119     _defaults = {
120         'button_text': "Have a Question? Chat with us.",
121         'input_placeholder': "How may I help you?",
122         'default_message': '',
123         'user_ids': _default_user_ids,
124         'image': _get_default_image,
125     }
126
127     def get_available_users(self, cr, uid, channel_id, context=None):
128         """ get available user of a given channel """
129         channel = self.browse(cr, uid, channel_id, context=context)
130         users = []
131         for user_id in channel.user_ids:
132             if (user_id.im_status == 'online'):
133                 users.append(user_id)
134         return users
135
136     def get_channel_session(self, cr, uid, channel_id, anonymous_name, context=None):
137         """ return a session given a channel : create on with a registered user, or return false otherwise """
138         # get the avalable user of the channel
139         users = self.get_available_users(cr, uid, channel_id, context=context)
140         if len(users) == 0:
141             return False
142         user_id = random.choice(users).id
143         # create the session, and add the link with the given channel
144         Session = self.pool["im_chat.session"]
145         newid = Session.create(cr, uid, {'user_ids': [(4, user_id)], 'channel_id': channel_id, 'anonymous_name' : anonymous_name}, context=context)
146         return Session.session_info(cr, uid, [newid], context=context)
147
148     def test_channel(self, cr, uid, channel, context=None):
149         if not channel:
150             return {}
151         return {
152             'url': self.browse(cr, uid, channel[0], context=context or {}).web_page,
153             'type': 'ir.actions.act_url'
154         }
155
156     def get_info_for_chat_src(self, cr, uid, channel, context=None):
157         url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
158         chan = self.browse(cr, uid, channel, context=context)
159         return {
160             "url": url,
161             'buttonText': chan.button_text,
162             'inputPlaceholder': chan.input_placeholder,
163             'defaultMessage': chan.default_message,
164             "channelName": chan.name,
165         }
166
167     def join(self, cr, uid, ids, context=None):
168         self.write(cr, uid, ids, {'user_ids': [(4, uid)]})
169         return True
170
171     def quit(self, cr, uid, ids, context=None):
172         self.write(cr, uid, ids, {'user_ids': [(3, uid)]})
173         return True
174
175 class im_chat_session(osv.Model):
176     _inherit = 'im_chat.session'
177
178     def _get_fullname(self, cr, uid, ids, fields, arg, context=None):
179         """ built the complete name of the session """
180         result = {}
181         sessions = self.browse(cr, uid, ids, context=context)
182         for session in sessions:
183             names = []
184             for user in session.user_ids:
185                 names.append(user.name)
186             if session.anonymous_name:
187                 names.append(session.anonymous_name)
188             result[session.id] = ', '.join(names)
189         return result
190
191     _columns = {
192         'anonymous_name' : fields.char('Anonymous Name'),
193         'channel_id': fields.many2one("im_livechat.channel", "Channel"),
194         'fullname' : fields.function(_get_fullname, type="char", string="Complete name"),
195     }
196
197     def is_in_session(self, cr, uid, uuid, user_id, context=None):
198         """ return if the given user_id is in the session """
199         sids = self.search(cr, uid, [('uuid', '=', uuid)], context=context, limit=1)
200         for session in self.browse(cr, uid, sids, context=context):
201             if session.anonymous_name and user_id == openerp.SUPERUSER_ID:
202                 return True
203             else:
204                 return super(im_chat_session, self).is_in_session(cr, uid, uuid, user_id, context=context)
205         return False
206
207     def users_infos(self, cr, uid, ids, context=None):
208         """ add the anonymous user in the user of the session """
209         for session in self.browse(cr, uid, ids, context=context):
210             users_infos = super(im_chat_session, self).users_infos(cr, uid, ids, context=context)
211             if session.anonymous_name:
212                 users_infos.append({'id' : False, 'name' : session.anonymous_name, 'im_status' : 'online'})
213             return users_infos
214
215
216 class LiveChatController(http.Controller):
217
218     @http.route('/im_livechat/support/<string:dbname>/<int:channel_id>', type='http', auth='none')
219     def support_page(self, dbname, channel_id, **kwargs):
220         registry, cr, uid, context = openerp.modules.registry.RegistryManager.get(dbname), request.cr, openerp.SUPERUSER_ID, request.context
221         info = registry.get('im_livechat.channel').get_info_for_chat_src(cr, uid, channel_id)
222         info["dbname"] = dbname
223         info["channel"] = channel_id
224         info["channel_name"] = registry.get('im_livechat.channel').read(cr, uid, channel_id, ['name'], context=context)["name"]
225         return request.render('im_livechat.support_page', info)
226
227     @http.route('/im_livechat/loader/<string:dbname>/<int:channel_id>', type='http', auth='none')
228     def loader(self, dbname, channel_id, **kwargs):
229         registry, cr, uid, context = openerp.modules.registry.RegistryManager.get(dbname), request.cr, openerp.SUPERUSER_ID, request.context
230         info = registry.get('im_livechat.channel').get_info_for_chat_src(cr, uid, channel_id)
231         info["dbname"] = dbname
232         info["channel"] = channel_id
233         info["username"] = kwargs.get("username", "Visitor")
234         return request.render('im_livechat.loader', info)
235
236     @http.route('/im_livechat/get_session', type="json", auth="none")
237     def get_session(self, channel_id, anonymous_name, **kwargs):
238         cr, uid, context, db = request.cr, request.uid or openerp.SUPERUSER_ID, request.context, request.db
239         reg = openerp.modules.registry.RegistryManager.get(db)
240         # if geoip, add the country name to the anonymous name
241         if hasattr(request, 'geoip'):
242             anonymous_name = anonymous_name + " ("+request.geoip.get('country_name', "")+")"
243         return reg.get("im_livechat.channel").get_channel_session(cr, uid, channel_id, anonymous_name, context=context)
244
245     @http.route('/im_livechat/available', type='json', auth="none")
246     def available(self, db, channel):
247         cr, uid, context, db = request.cr, request.uid or openerp.SUPERUSER_ID, request.context, request.db
248         reg = openerp.modules.registry.RegistryManager.get(db)
249         with reg.cursor() as cr:
250             return len(reg.get('im_livechat.channel').get_available_users(cr, uid, channel)) > 0
251