11 changed files with 2099 additions and 0 deletions
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2009-TODAY Cybrosys Technologies(<http://www.cybrosys.com>). |
|||
# Author: Nilmar Shereef(<http://www.cybrosys.com>) |
|||
# you can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|||
# of the Software or modified copies of the Software. |
|||
# |
|||
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################## |
@ -0,0 +1,41 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2009-TODAY Cybrosys Technologies(<http://www.cybrosys.com>). |
|||
# Author: Nilmar Shereef(<http://www.cybrosys.com>) |
|||
# you can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|||
# of the Software or modified copies of the Software. |
|||
# |
|||
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################## |
|||
{ |
|||
'name': 'Sent Mails', |
|||
'version': '1.0', |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'website': 'http://www.cybrosys.com', |
|||
"category": "Discuss", |
|||
'depends': ['base', 'mail'], |
|||
'license': 'AGPL-3', |
|||
'data': [ |
|||
'views/get_sent_mails.xml', |
|||
], |
|||
'qweb': [ |
|||
'static/src/xml/client_action_sent_mails.xml', |
|||
|
|||
], |
|||
'installable': True, |
|||
'auto_install': False |
|||
} |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 54 KiB |
@ -0,0 +1,44 @@ |
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h2 class="oe_slogan">Show sent mails</h2> |
|||
<h3 class="oe_slogan">Shows the mails or discussions sent by current user</h3> |
|||
<h4 class="oe_slogan">Author : Cybrosys Techno Solutions, www.cybrosys.com</h4> |
|||
</div> |
|||
|
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<p class='oe_mt32'> |
|||
☛This module enables the feature to display the mails and discussions done by current user |
|||
</p> |
|||
<div class="oe_centeralign oe_websiteonly"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="oe_row"> |
|||
<h2 class="oe_slogan">Sent Mail Menu Under Discuss</h2> |
|||
<div class="oe_span6"> |
|||
<div class="oe_row_img oe_centered"> |
|||
<img class="oe_picture oe_screenshot" src="sent_mails_demo.png"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> |
|||
<div class="oe_slogan" style="margin-top:10px !important;"> |
|||
<a class="btn btn-primary btn-lg mt8" |
|||
style="color: #FFFFFF !important;" href="http://www.cybrosys.com"><i |
|||
class="fa fa-envelope"></i> Email </a> <a |
|||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;" |
|||
href="http://www.cybrosys.com/contact/"><i |
|||
class="fa fa-phone"></i> Contact Us </a> <a |
|||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;" |
|||
href="http://www.cybrosys.com/odoo-customization-and-installation/"><i |
|||
class="fa fa-check-square"></i> Request Customization </a> |
|||
</div> |
|||
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> |
|||
</section> |
After Width: | Height: | Size: 52 KiB |
@ -0,0 +1,180 @@ |
|||
#!/usr/bin/env python |
|||
# -*- coding: utf-8 -*- |
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details. |
|||
""" |
|||
openerp_mailgate.py |
|||
""" |
|||
|
|||
import cgitb |
|||
import time |
|||
import optparse |
|||
import sys |
|||
import xmlrpclib |
|||
import smtplib |
|||
from email.mime.multipart import MIMEMultipart |
|||
from email.mime.base import MIMEBase |
|||
from email.mime.text import MIMEText |
|||
from email.utils import COMMASPACE, formatdate |
|||
from email import Encoders |
|||
|
|||
class DefaultConfig(object): |
|||
""" |
|||
Default configuration |
|||
""" |
|||
OPENERP_DEFAULT_USER_ID = 1 |
|||
OPENERP_DEFAULT_PASSWORD = 'admin' |
|||
OPENERP_HOSTNAME = 'localhost' |
|||
OPENERP_PORT = 8069 |
|||
OPENERP_DEFAULT_DATABASE = 'openerp' |
|||
MAIL_ERROR = 'error@example.com' |
|||
MAIL_SERVER = 'smtp.example.com' |
|||
MAIL_SERVER_PORT = 25 |
|||
MAIL_ADMINS = ('info@example.com',) |
|||
|
|||
config = DefaultConfig() |
|||
|
|||
|
|||
def send_mail(_from_, to_, subject, text, files=None, server=config.MAIL_SERVER, port=config.MAIL_SERVER_PORT): |
|||
assert isinstance(to_, (list, tuple)) |
|||
|
|||
if files is None: |
|||
files = [] |
|||
|
|||
msg = MIMEMultipart() |
|||
msg['From'] = _from_ |
|||
msg['To'] = COMMASPACE.join(to_) |
|||
msg['Date'] = formatdate(localtime=True) |
|||
msg['Subject'] = subject |
|||
|
|||
msg.attach( MIMEText(text) ) |
|||
|
|||
for file_name, file_content in files: |
|||
part = MIMEBase('application', "octet-stream") |
|||
part.set_payload( file_content ) |
|||
Encoders.encode_base64(part) |
|||
part.add_header('Content-Disposition', 'attachment; filename="%s"' |
|||
% file_name) |
|||
msg.attach(part) |
|||
|
|||
smtp = smtplib.SMTP(server, port=port) |
|||
smtp.sendmail(_from_, to_, msg.as_string() ) |
|||
smtp.close() |
|||
|
|||
class RPCProxy(object): |
|||
def __init__(self, uid, passwd, |
|||
host=config.OPENERP_HOSTNAME, |
|||
port=config.OPENERP_PORT, |
|||
path='object', |
|||
dbname=config.OPENERP_DEFAULT_DATABASE): |
|||
self.rpc = xmlrpclib.ServerProxy('http://%s:%s/xmlrpc/%s' % (host, port, path), allow_none=True) |
|||
self.user_id = uid |
|||
self.passwd = passwd |
|||
self.dbname = dbname |
|||
|
|||
def __call__(self, *request, **kwargs): |
|||
return self.rpc.execute(self.dbname, self.user_id, self.passwd, *request, **kwargs) |
|||
|
|||
class EmailParser(object): |
|||
def __init__(self, uid, password, dbname, host, port, model=False, email_default=False): |
|||
self.rpc = RPCProxy(uid, password, host=host, port=port, dbname=dbname) |
|||
if model: |
|||
try: |
|||
self.model_id = int(model) |
|||
self.model = str(model) |
|||
except: |
|||
self.model_id = self.rpc('ir.model', 'search', [('model', '=', model)])[0] |
|||
self.model = str(model) |
|||
self.email_default = email_default |
|||
|
|||
|
|||
def parse(self, message, custom_values=None, save_original=None): |
|||
# pass message as bytes because we don't know its encoding until we parse its headers |
|||
# and hence can't convert it to utf-8 for transport |
|||
return self.rpc('mail.thread', |
|||
'message_process', |
|||
self.model, |
|||
xmlrpclib.Binary(message), |
|||
custom_values or {}, |
|||
save_original or False) |
|||
|
|||
def configure_parser(): |
|||
parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog v1.1') |
|||
group = optparse.OptionGroup(parser, "Note", |
|||
"This program parse a mail from standard input and communicate " |
|||
"with the Odoo server for case management in the CRM module.") |
|||
parser.add_option_group(group) |
|||
parser.add_option("-u", "--user", dest="userid", |
|||
help="Odoo user id to connect with", |
|||
default=config.OPENERP_DEFAULT_USER_ID, type='int') |
|||
parser.add_option("-p", "--password", dest="password", |
|||
help="Odoo user password", |
|||
default=config.OPENERP_DEFAULT_PASSWORD) |
|||
parser.add_option("-o", "--model", dest="model", |
|||
help="Name or ID of destination model", |
|||
default="crm.lead") |
|||
parser.add_option("-m", "--default", dest="default", |
|||
help="Admin email for error notifications.", |
|||
default=None) |
|||
parser.add_option("-d", "--dbname", dest="dbname", |
|||
help="Odoo database name (default: %default)", |
|||
default=config.OPENERP_DEFAULT_DATABASE) |
|||
parser.add_option("--host", dest="host", |
|||
help="Odoo Server hostname", |
|||
default=config.OPENERP_HOSTNAME) |
|||
parser.add_option("--port", dest="port", |
|||
help="Odoo Server XML-RPC port number", |
|||
default=config.OPENERP_PORT) |
|||
parser.add_option("--custom-values", dest="custom_values", |
|||
help="Dictionary of extra values to pass when creating records", |
|||
default=None) |
|||
parser.add_option("-s", dest="save_original", |
|||
action="store_true", |
|||
help="Keep a full copy of the email source attached to each message", |
|||
default=False) |
|||
|
|||
return parser |
|||
|
|||
def main(): |
|||
""" |
|||
Receive the email via the stdin and send it to the OpenERP Server |
|||
""" |
|||
|
|||
parser = configure_parser() |
|||
(options, args) = parser.parse_args() |
|||
email_parser = EmailParser(options.userid, |
|||
options.password, |
|||
options.dbname, |
|||
options.host, |
|||
options.port, |
|||
model=options.model, |
|||
email_default= options.default) |
|||
msg_txt = sys.stdin.read() |
|||
custom_values = {} |
|||
try: |
|||
custom_values = dict(eval(options.custom_values or "{}" )) |
|||
except: |
|||
import traceback |
|||
traceback.print_exc() |
|||
|
|||
try: |
|||
email_parser.parse(msg_txt, custom_values, options.save_original or False) |
|||
except Exception: |
|||
msg = '\n'.join([ |
|||
'parameters', |
|||
'==========', |
|||
'%r' % (options,), |
|||
'traceback', |
|||
'=========', |
|||
'%s' % (cgitb.text(sys.exc_info())), |
|||
]) |
|||
|
|||
subject = '[Odoo]:ERROR: Mailgateway - %s' % time.strftime('%Y-%m-%d %H:%M:%S') |
|||
send_mail( |
|||
config.MAIL_ERROR, |
|||
config.MAIL_ADMINS, |
|||
subject, msg, files=[('message.txt', msg_txt)] |
|||
) |
|||
sys.stderr.write("Failed to deliver email to Odoo Server, sending error notification to %s\n" % config.MAIL_ADMINS) |
|||
|
|||
if __name__ == '__main__': |
|||
main() |
File diff suppressed because it is too large
@ -0,0 +1,666 @@ |
|||
odoo.define('mail.chat_client_action', function (require) { |
|||
"use strict"; |
|||
|
|||
var chat_manager = require('mail.chat_manager'); |
|||
var composer = require('mail.composer'); |
|||
var ChatThread = require('mail.ChatThread'); |
|||
|
|||
var config = require('web.config'); |
|||
var ControlPanelMixin = require('web.ControlPanelMixin'); |
|||
var core = require('web.core'); |
|||
var data = require('web.data'); |
|||
var Dialog = require('web.Dialog'); |
|||
var framework = require('web.framework'); |
|||
var Model = require('web.Model'); |
|||
|
|||
var pyeval = require('web.pyeval'); |
|||
var SearchView = require('web.SearchView'); |
|||
var Widget = require('web.Widget'); |
|||
|
|||
var QWeb = core.qweb; |
|||
var _t = core._t; |
|||
|
|||
/** |
|||
* Widget : Invite People to Channel Dialog |
|||
* |
|||
* Popup containing a 'many2many_tags' custom input to select multiple partners. |
|||
* Search user according to the input, and trigger event when selection is validated. |
|||
**/ |
|||
var PartnerInviteDialog = Dialog.extend({ |
|||
dialog_title: _t('Invite people'), |
|||
template: "mail.PartnerInviteDialog", |
|||
init: function(parent, title, channel_id){ |
|||
this.channel_id = channel_id; |
|||
|
|||
this._super(parent, { |
|||
title: title, |
|||
size: "medium", |
|||
buttons: [{ |
|||
text: _t("Invite"), |
|||
close: true, |
|||
classes: "btn-primary", |
|||
click: _.bind(this.on_click_add, this), |
|||
}], |
|||
}); |
|||
this.PartnersModel = new Model('res.partner'); |
|||
}, |
|||
start: function(){ |
|||
var self = this; |
|||
this.$input = this.$('.o_mail_chat_partner_invite_input'); |
|||
this.$input.select2({ |
|||
width: '100%', |
|||
allowClear: true, |
|||
multiple: true, |
|||
formatResult: function(item) { |
|||
var status = QWeb.render('mail.chat.UserStatus', {status: item.im_status}); |
|||
return $('<span>').text(item.text).prepend(status); |
|||
}, |
|||
query: function (query) { |
|||
self.PartnersModel.call('im_search', [query.term, 20]).then(function(result){ |
|||
var data = []; |
|||
_.each(result, function(partner){ |
|||
partner.text = partner.name; |
|||
data.push(partner); |
|||
}); |
|||
query.callback({results: data}); |
|||
}); |
|||
} |
|||
}); |
|||
return this._super.apply(this, arguments); |
|||
}, |
|||
on_click_add: function(){ |
|||
var self = this; |
|||
var data = this.$input.select2('data'); |
|||
if(data.length >= 1){ |
|||
var ChannelModel = new Model('mail.channel'); |
|||
return ChannelModel.call('channel_invite', [], {ids : [this.channel_id], partner_ids: _.pluck(data, 'id')}) |
|||
.then(function(){ |
|||
var names = _.escape(_.pluck(data, 'text').join(', ')); |
|||
var notification = _.str.sprintf(_t('You added <b>%s</b> to the conversation.'), names); |
|||
self.do_notify(_t('New people'), notification); |
|||
}); |
|||
} |
|||
}, |
|||
}); |
|||
|
|||
var ChatAction = Widget.extend(ControlPanelMixin, { |
|||
template: 'mail.client_action', |
|||
|
|||
events: { |
|||
"click .o_mail_chat_channel_item": function (event) { |
|||
event.preventDefault(); |
|||
var channel_id = this.$(event.currentTarget).data('channel-id'); |
|||
this.set_channel(chat_manager.get_channel(channel_id)); |
|||
}, |
|||
"click .o_mail_sidebar_title .o_add": function (event) { |
|||
event.preventDefault(); |
|||
var type = $(event.target).data("type"); |
|||
this.$('.o_mail_add_channel[data-type=' + type + ']') |
|||
.show() |
|||
.find("input").focus(); |
|||
}, |
|||
"blur .o_mail_add_channel input": function () { |
|||
this.$('.o_mail_add_channel') |
|||
.hide(); |
|||
}, |
|||
"click .o_mail_partner_unpin": function (event) { |
|||
event.stopPropagation(); |
|||
var channel_id = $(event.target).data("channel-id"); |
|||
this.unsubscribe_from_channel(chat_manager.get_channel(channel_id)); |
|||
}, |
|||
"click .o_snackbar_undo": function (event) { |
|||
event.preventDefault(); |
|||
var channel = this.channel; |
|||
this.$snackbar.remove(); |
|||
this.clear_needactions_def.then(function (msgs_ids) { |
|||
chat_manager.undo_mark_as_read(msgs_ids, channel); |
|||
}); |
|||
}, |
|||
"click .o_mail_annoying_notification_bar .fa-close": function () { |
|||
this.$(".o_mail_annoying_notification_bar").slideUp(); |
|||
}, |
|||
"click .o_mail_request_permission": function (event) { |
|||
event.preventDefault(); |
|||
this.$(".o_mail_annoying_notification_bar").slideUp(); |
|||
var def = window.Notification.requestPermission(); |
|||
if (def) { |
|||
def.then(function () { |
|||
chat_manager.send_native_notification('Permission granted', 'Odoo has now the permission to send you native notifications on this device.'); |
|||
}); |
|||
} |
|||
}, |
|||
"keydown": function (event) { |
|||
if (event.which === $.ui.keyCode.ESCAPE && this.selected_message) { |
|||
this.unselect_message(); |
|||
} |
|||
}, |
|||
}, |
|||
|
|||
on_attach_callback: function () { |
|||
chat_manager.bus.trigger('client_action_open', true); |
|||
if (this.channel) { |
|||
this.thread.scroll_to({offset: this.channels_scrolltop[this.channel.id]}); |
|||
} |
|||
}, |
|||
on_detach_callback: function () { |
|||
chat_manager.bus.trigger('client_action_open', false); |
|||
this.channels_scrolltop[this.channel.id] = this.thread.get_scrolltop(); |
|||
}, |
|||
|
|||
init: function(parent, action, options) { |
|||
this._super.apply(this, arguments); |
|||
this.action_manager = parent; |
|||
this.domain = []; |
|||
this.action = action; |
|||
this.options = options || {}; |
|||
this.channels_scrolltop = {}; |
|||
this.throttled_render_sidebar = _.throttle(this.render_sidebar.bind(this), 100, { leading: false }); |
|||
this.notification_bar = (window.Notification && window.Notification.permission === "default"); |
|||
this.selected_message = null; |
|||
}, |
|||
|
|||
willStart: function () { |
|||
return chat_manager.is_ready; |
|||
}, |
|||
|
|||
start: function() { |
|||
var self = this; |
|||
|
|||
// create searchview
|
|||
var options = { |
|||
$buttons: $("<div>"), |
|||
action: this.action, |
|||
disable_groupby: true, |
|||
}; |
|||
var dataset = new data.DataSetSearch(this, 'mail.message'); |
|||
var view_id = (this.action && this.action.search_view_id && this.action.search_view_id[0]) || false; |
|||
var default_channel_id = this.options.active_id || |
|||
this.action.context.active_id || |
|||
this.action.params.default_active_id || |
|||
'channel_inbox'; |
|||
var default_channel = chat_manager.get_channel(default_channel_id) || |
|||
chat_manager.get_channel('channel_inbox'); |
|||
|
|||
this.searchview = new SearchView(this, dataset, view_id, {}, options); |
|||
this.searchview.on('search_data', this, this.on_search); |
|||
|
|||
this.basic_composer = new composer.BasicComposer(this, {mention_partners_restricted: true}); |
|||
this.extended_composer = new composer.ExtendedComposer(this, {mention_partners_restricted: true}); |
|||
this.thread = new ChatThread(this, { |
|||
display_help: true, |
|||
shorten_messages: false, |
|||
}); |
|||
|
|||
this.$buttons = $(QWeb.render("mail.chat.ControlButtons", {})); |
|||
this.$buttons.find('button').css({display:"inline-block"}); |
|||
this.$buttons.on('click', '.o_mail_chat_button_invite', this.on_click_button_invite); |
|||
this.$buttons.on('click', '.o_mail_chat_button_unsubscribe', this.on_click_button_unsubscribe); |
|||
this.$buttons.on('click', '.o_mail_chat_button_settings', this.on_click_button_settings); |
|||
this.$buttons.on('click', '.o_mail_toggle_channels', function () { |
|||
self.$('.o_mail_chat_sidebar').slideToggle(200); |
|||
}); |
|||
this.$buttons.on('click', '.o_mail_chat_button_mark_read', function () { |
|||
chat_manager.mark_all_as_read(self.channel, self.domain); |
|||
}); |
|||
this.$buttons.on('click', '.o_mail_chat_button_unstar_all', chat_manager.unstar_all); |
|||
this.$buttons.on('click', '.o_mail_chat_button_new_message', this.on_click_new_message); |
|||
this.$buttons.on('click', '.o_mail_chat_button_new_message_sent', this.on_click_new_message); |
|||
|
|||
this.thread.on('redirect', this, function (res_model, res_id) { |
|||
chat_manager.redirect(res_model, res_id, this.set_channel.bind(this)); |
|||
}); |
|||
this.thread.on('redirect_to_channel', this, function (channel_id) { |
|||
chat_manager.join_channel(channel_id).then(this.set_channel.bind(this)); |
|||
}); |
|||
this.thread.on('load_more_messages', this, this.load_more_messages); |
|||
this.thread.on('mark_as_read', this, function (message_id) { |
|||
chat_manager.mark_as_read([message_id]); |
|||
}); |
|||
this.thread.on('toggle_star_status', this, function (message_id) { |
|||
chat_manager.toggle_star_status(message_id); |
|||
}); |
|||
this.thread.on('select_message', this, this.select_message); |
|||
this.thread.on('unselect_message', this, this.unselect_message); |
|||
|
|||
this.basic_composer.on('post_message', this, this.on_post_message); |
|||
this.basic_composer.on('input_focused', this, this.on_composer_input_focused); |
|||
this.extended_composer.on('post_message', this, this.on_post_message); |
|||
this.extended_composer.on('input_focused', this, this.on_composer_input_focused); |
|||
|
|||
var def1 = this.thread.appendTo(this.$('.o_mail_chat_content')); |
|||
var def2 = this.basic_composer.appendTo(this.$('.o_mail_chat_content')); |
|||
var def3 = this.extended_composer.appendTo(this.$('.o_mail_chat_content')); |
|||
var def4 = this.searchview.appendTo($("<div>")).then(function () { |
|||
self.$searchview_buttons = self.searchview.$buttons.contents(); |
|||
}); |
|||
|
|||
this.render_sidebar(); |
|||
|
|||
return $.when(def1, def2, def3, def4) |
|||
.then(this.set_channel.bind(this, default_channel)) |
|||
.then(function () { |
|||
chat_manager.bus.on('open_channel', self, self.set_channel); |
|||
chat_manager.bus.on('new_message', self, self.on_new_message); |
|||
chat_manager.bus.on('update_message', self, self.on_update_message); |
|||
chat_manager.bus.on('new_channel', self, self.on_new_channel); |
|||
chat_manager.bus.on('anyone_listening', self, function (channel, query) { |
|||
query.is_displayed = query.is_displayed || (channel.id === self.channel.id && self.thread.is_at_bottom()); |
|||
}); |
|||
chat_manager.bus.on('unsubscribe_from_channel', self, self.render_sidebar); |
|||
chat_manager.bus.on('update_needaction', self, self.throttled_render_sidebar); |
|||
chat_manager.bus.on('update_channel_unread_counter', self, self.throttled_render_sidebar); |
|||
chat_manager.bus.on('update_dm_presence', self, self.throttled_render_sidebar); |
|||
self.thread.$el.on("scroll", null, _.debounce(function () { |
|||
if (self.thread.is_at_bottom()) { |
|||
chat_manager.mark_channel_as_seen(self.channel); |
|||
} |
|||
}, 100)); |
|||
}); |
|||
}, |
|||
|
|||
select_message: function(message_id) { |
|||
this.$el.addClass('o_mail_selection_mode'); |
|||
var message = chat_manager.get_message(message_id); |
|||
this.selected_message = message; |
|||
var subject = "Re: " + message.record_name; |
|||
this.extended_composer.set_subject(subject); |
|||
if (this.channel.type !== 'static') { |
|||
this.basic_composer.toggle(false); |
|||
} |
|||
this.extended_composer.toggle(true); |
|||
this.thread.scroll_to({id: message_id, duration: 200, only_if_necessary: true}); |
|||
this.extended_composer.focus('body'); |
|||
}, |
|||
|
|||
unselect_message: function() { |
|||
this.basic_composer.toggle(this.channel.type !== 'static' && !this.channel.mass_mailing); |
|||
this.extended_composer.toggle(this.channel.type !== 'static' && this.channel.mass_mailing); |
|||
if (!config.device.touch) { |
|||
var composer = this.channel.mass_mailing ? this.extended_composer : this.basic_composer; |
|||
composer.focus(); |
|||
} |
|||
this.$el.removeClass('o_mail_selection_mode'); |
|||
this.thread.unselect(); |
|||
this.selected_message = null; |
|||
}, |
|||
|
|||
render_sidebar: function () { |
|||
var self = this; |
|||
var $sidebar = $(QWeb.render("mail.chat.Sidebar", { |
|||
active_channel_id: this.channel ? this.channel.id: undefined, |
|||
channels: chat_manager.get_channels(), |
|||
needaction_counter: chat_manager.get_needaction_counter(), |
|||
})); |
|||
this.$(".o_mail_chat_sidebar").html($sidebar.contents()); |
|||
|
|||
this.$('.o_mail_add_channel[data-type=public]').find("input").autocomplete({ |
|||
source: function(request, response) { |
|||
self.last_search_val = _.escape(request.term); |
|||
self.do_search_channel(self.last_search_val).done(function(result){ |
|||
result.push({ |
|||
'label': _.str.sprintf('<strong>'+_t("Create %s")+'</strong>', '<em>"#'+self.last_search_val+'"</em>'), |
|||
'value': '_create', |
|||
}); |
|||
response(result); |
|||
}); |
|||
}, |
|||
select: function(event, ui) { |
|||
if (self.last_search_val) { |
|||
if (ui.item.value === '_create') { |
|||
chat_manager.create_channel(self.last_search_val, "public"); |
|||
} else { |
|||
chat_manager.join_channel(ui.item.id); |
|||
} |
|||
} |
|||
}, |
|||
focus: function(event) { |
|||
event.preventDefault(); |
|||
}, |
|||
html: true, |
|||
}); |
|||
|
|||
this.$('.o_mail_add_channel[data-type=dm]').find("input").autocomplete({ |
|||
source: function(request, response) { |
|||
self.last_search_val = _.escape(request.term); |
|||
chat_manager.search_partner(self.last_search_val).done(response); |
|||
}, |
|||
select: function(event, ui) { |
|||
var partner_id = ui.item.id; |
|||
chat_manager.create_channel(partner_id, "dm"); |
|||
}, |
|||
focus: function(event) { |
|||
event.preventDefault(); |
|||
}, |
|||
html: true, |
|||
}); |
|||
|
|||
this.$('.o_mail_add_channel[data-type=private]').find("input").on('keyup', this, function (event) { |
|||
var name = _.escape($(event.target).val()); |
|||
if(event.which === $.ui.keyCode.ENTER && name) { |
|||
chat_manager.create_channel(name, "private"); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
render_snackbar: function (template, context, timeout) { |
|||
if (this.$snackbar) { |
|||
this.$snackbar.remove(); |
|||
} |
|||
timeout = timeout || 20000; |
|||
this.$snackbar = $(QWeb.render(template, context)); |
|||
this.$('.o_mail_chat_content').append(this.$snackbar); |
|||
// Hide snackbar after [timeout] milliseconds (by default, 20s)
|
|||
var $snackbar = this.$snackbar; |
|||
setTimeout(function() { $snackbar.fadeOut(); }, timeout); |
|||
}, |
|||
|
|||
do_search_channel: function(search_val){ |
|||
var Channel = new Model("mail.channel"); |
|||
return Channel.call('channel_search_to_join', [search_val]).then(function(result){ |
|||
var values = []; |
|||
_.each(result, function(channel){ |
|||
var escaped_name = _.escape(channel.name); |
|||
values.push(_.extend(channel, { |
|||
'value': escaped_name, |
|||
'label': escaped_name, |
|||
})); |
|||
}); |
|||
return values; |
|||
}); |
|||
}, |
|||
|
|||
set_channel: function (channel) { |
|||
var self = this; |
|||
// Store scroll position of previous channel
|
|||
if (this.channel) { |
|||
this.channels_scrolltop[this.channel.id] = this.thread.get_scrolltop(); |
|||
} |
|||
var new_channel_scrolltop = this.channels_scrolltop[channel.id]; |
|||
|
|||
this.channel = channel; |
|||
this.messages_separator_position = undefined; // reset value on channel change
|
|||
this.unread_counter = this.channel.unread_counter; |
|||
this.last_seen_message_id = this.channel.last_seen_message_id; |
|||
this.clear_needactions_def = $.Deferred(); |
|||
if (this.$snackbar) { |
|||
this.$snackbar.remove(); |
|||
} |
|||
|
|||
this.action.context.active_id = channel.id; |
|||
this.action.context.active_ids = [channel.id]; |
|||
|
|||
return this.fetch_and_render_thread().then(function () { |
|||
// Mark channel's messages as read and clear needactions
|
|||
if (channel.type !== 'static') { |
|||
// Display snackbar if needactions have been cleared
|
|||
if (channel.needaction_counter > 0) { |
|||
self.render_snackbar('mail.chat.UndoSnackbar', { |
|||
nb_needactions: channel.needaction_counter, |
|||
}); |
|||
} |
|||
chat_manager.mark_channel_as_seen(channel); |
|||
self.clear_needactions_def = chat_manager.mark_all_as_read(channel); |
|||
} |
|||
|
|||
// Update control panel
|
|||
self.set("title", '#' + channel.name); |
|||
// Hide 'invite', 'unsubscribe' and 'settings' buttons in static channels and DM
|
|||
self.$buttons |
|||
.find('.o_mail_chat_button_invite, .o_mail_chat_button_unsubscribe, .o_mail_chat_button_settings') |
|||
.toggle(channel.type !== "dm" && channel.type !== 'static'); |
|||
self.$buttons |
|||
.find('.o_mail_chat_button_mark_read, .o_mail_chat_button_new_message') |
|||
.toggle(channel.id === "channel_inbox"); |
|||
self.$buttons |
|||
.find('.o_mail_chat_button_new_message_sent') |
|||
.toggle(channel.id === "channel_sent"); |
|||
self.$buttons |
|||
.find('.o_mail_chat_button_unstar_all') |
|||
.toggle(channel.id === "channel_starred"); |
|||
|
|||
self.$('.o_mail_chat_channel_item') |
|||
.removeClass('o_active') |
|||
.filter('[data-channel-id=' + channel.id + ']') |
|||
.removeClass('o_unread_message') |
|||
.addClass('o_active'); |
|||
|
|||
var $new_messages_separator = self.$('.o_thread_new_messages_separator'); |
|||
if ($new_messages_separator.length) { |
|||
self.thread.$el.scrollTo($new_messages_separator); |
|||
} else { |
|||
self.thread.scroll_to({offset: new_channel_scrolltop}); |
|||
} |
|||
|
|||
// Update control panel before focusing the composer, otherwise focus is on the searchview
|
|||
self.update_cp(); |
|||
if (config.device.size_class === config.device.SIZES.XS) { |
|||
self.$('.o_mail_chat_sidebar').hide(); |
|||
} |
|||
|
|||
// Display and focus the adequate composer, and unselect possibly selected message
|
|||
// to prevent sending messages as reply to that message
|
|||
self.unselect_message(); |
|||
|
|||
self.action_manager.do_push_state({ |
|||
action: self.action.id, |
|||
active_id: self.channel.id, |
|||
}); |
|||
}); |
|||
}, |
|||
unsubscribe_from_channel: function (channel) { |
|||
var self = this; |
|||
chat_manager |
|||
.unsubscribe(channel) |
|||
.then(this.render_sidebar.bind(this)) |
|||
.then(this.set_channel.bind(this, chat_manager.get_channel("channel_inbox"))) |
|||
.then(function () { |
|||
if (_.contains(['public', 'private'], channel.type)) { |
|||
var msg = _.str.sprintf(_t('You unsubscribed from <b>%s</b>.'), channel.name); |
|||
self.do_notify(_t("Unsubscribed"), msg); |
|||
} |
|||
delete self.channels_scrolltop[channel.id]; |
|||
}); |
|||
}, |
|||
|
|||
get_thread_rendering_options: function (messages) { |
|||
// Compute position of the 'New messages' separator, only once when joining
|
|||
// a channel to keep it in the thread when new messages arrive
|
|||
if (_.isUndefined(this.messages_separator_position)) { |
|||
if (!this.unread_counter) { |
|||
this.messages_separator_position = false; // no unread message -> don't display separator
|
|||
} else { |
|||
var msg = chat_manager.get_last_seen_message(this.channel); |
|||
this.messages_separator_position = msg ? msg.id : 'top'; |
|||
} |
|||
} |
|||
return { |
|||
channel_id: this.channel.id, |
|||
display_load_more: !chat_manager.all_history_loaded(this.channel, this.domain), |
|||
display_needactions: this.channel.display_needactions, |
|||
messages_separator_position: this.messages_separator_position, |
|||
squash_close_messages: this.channel.type !== 'static' && !this.channel.mass_mailing, |
|||
display_empty_channel: !messages.length && !this.domain.length, |
|||
display_no_match: !messages.length && this.domain.length, |
|||
display_subject: this.channel.mass_mailing || this.channel.id === "channel_inbox", |
|||
display_reply_icon: true, |
|||
}; |
|||
}, |
|||
|
|||
fetch_and_render_thread: function () { |
|||
var self = this; |
|||
return chat_manager.get_messages({channel_id: this.channel.id, domain: this.domain}).then(function(result) { |
|||
self.thread.render(result, self.get_thread_rendering_options(result)); |
|||
self.update_button_status(result.length === 0); |
|||
}); |
|||
}, |
|||
|
|||
update_button_status: function (disabled) { |
|||
if (this.channel.id === "channel_inbox") { |
|||
this.$buttons |
|||
.find('.o_mail_chat_button_mark_read') |
|||
.toggleClass('disabled', disabled); |
|||
} |
|||
if (this.channel.id === "channel_starred") { |
|||
this.$buttons |
|||
.find('.o_mail_chat_button_unstar_all') |
|||
.toggleClass('disabled', disabled); |
|||
} |
|||
}, |
|||
|
|||
load_more_messages: function () { |
|||
var self = this; |
|||
var oldest_msg_id = this.$('.o_thread_message').first().data('messageId'); |
|||
var oldest_msg_selector = '.o_thread_message[data-message-id="' + oldest_msg_id + '"]'; |
|||
var offset = -framework.getPosition(document.querySelector(oldest_msg_selector)).top; |
|||
return chat_manager |
|||
.get_messages({channel_id: this.channel.id, domain: this.domain, load_more: true}) |
|||
.then(function(result) { |
|||
if (self.messages_separator_position === 'top') { |
|||
self.messages_separator_position = undefined; // reset value to re-compute separator position
|
|||
} |
|||
self.thread.render(result, self.get_thread_rendering_options(result)); |
|||
offset += framework.getPosition(document.querySelector(oldest_msg_selector)).top; |
|||
self.thread.scroll_to({offset: offset}); |
|||
}); |
|||
}, |
|||
|
|||
update_cp: function () { |
|||
this.update_control_panel({ |
|||
breadcrumbs: this.action_manager.get_breadcrumbs(), |
|||
cp_content: { |
|||
$buttons: this.$buttons, |
|||
$searchview: this.searchview.$el, |
|||
$searchview_buttons: this.$searchview_buttons, |
|||
}, |
|||
searchview: this.searchview, |
|||
}); |
|||
}, |
|||
|
|||
do_show: function () { |
|||
this._super.apply(this, arguments); |
|||
this.update_cp(); |
|||
this.action_manager.do_push_state({ |
|||
action: this.action.id, |
|||
active_id: this.channel.id, |
|||
}); |
|||
}, |
|||
|
|||
on_search: function (domains) { |
|||
var result = pyeval.sync_eval_domains_and_contexts({ |
|||
domains: domains |
|||
}); |
|||
|
|||
this.domain = result.domain; |
|||
this.fetch_and_render_thread(); |
|||
}, |
|||
|
|||
on_post_message: function (message) { |
|||
var self = this; |
|||
var options = this.selected_message ? {} : {channel_id: this.channel.id}; |
|||
if (this.selected_message) { |
|||
message.subtype = 'mail.mt_comment'; |
|||
message.subtype_id = false; |
|||
message.message_type = 'comment'; |
|||
message.content_subtype = 'html'; |
|||
|
|||
options.model = this.selected_message.model; |
|||
options.res_id = this.selected_message.res_id; |
|||
} |
|||
chat_manager |
|||
.post_message(message, options) |
|||
.then(function() { |
|||
if (self.selected_message) { |
|||
self.render_snackbar('mail.chat.MessageSentSnackbar', {record_name: self.selected_message.record_name}, 5000); |
|||
self.unselect_message(); |
|||
} else { |
|||
self.thread.scroll_to(); |
|||
} |
|||
}) |
|||
.fail(function () { |
|||
// todo: display notification
|
|||
}); |
|||
}, |
|||
on_new_message: function (message) { |
|||
var self = this; |
|||
if (_.contains(message.channel_ids, this.channel.id)) { |
|||
if (this.channel.type !== 'static' && this.thread.is_at_bottom()) { |
|||
chat_manager.mark_channel_as_seen(this.channel); |
|||
} |
|||
|
|||
var should_scroll = this.thread.is_at_bottom(); |
|||
this.fetch_and_render_thread().then(function () { |
|||
if (should_scroll) { |
|||
self.thread.scroll_to({id: message.id}); |
|||
} |
|||
}); |
|||
} |
|||
// Re-render sidebar to indicate that there is a new message in the corresponding channels
|
|||
this.render_sidebar(); |
|||
// Dump scroll position of channels in which the new message arrived
|
|||
this.channels_scrolltop = _.omit(this.channels_scrolltop, message.channel_ids); |
|||
}, |
|||
on_update_message: function (message) { |
|||
var self = this; |
|||
var current_channel_id = this.channel.id; |
|||
if ((current_channel_id === "channel_starred" && !message.is_starred) || |
|||
(current_channel_id === "channel_inbox" && !message.is_needaction)) { |
|||
chat_manager.get_messages({channel_id: this.channel.id, domain: this.domain}).then(function (messages) { |
|||
var options = self.get_thread_rendering_options(messages); |
|||
self.thread.remove_message_and_render(message.id, messages, options).then(function () { |
|||
self.update_button_status(messages.length === 0); |
|||
}); |
|||
}); |
|||
} else if (_.contains(message.channel_ids, current_channel_id)) { |
|||
this.fetch_and_render_thread(); |
|||
} |
|||
}, |
|||
on_new_channel: function (channel) { |
|||
this.render_sidebar(); |
|||
if (channel.autoswitch) { |
|||
this.set_channel(channel); |
|||
} |
|||
}, |
|||
on_composer_input_focused: function () { |
|||
var suggestions = chat_manager.get_mention_partner_suggestions(this.channel); |
|||
var composer = this.channel.mass_mailing ? this.extended_composer : this.basic_composer; |
|||
composer.mention_set_prefetched_partners(suggestions); |
|||
}, |
|||
|
|||
on_click_button_invite: function () { |
|||
var title = _.str.sprintf(_t('Invite people to #%s'), this.channel.name); |
|||
new PartnerInviteDialog(this, title, this.channel.id).open(); |
|||
}, |
|||
|
|||
on_click_button_unsubscribe: function () { |
|||
this.unsubscribe_from_channel(this.channel); |
|||
}, |
|||
on_click_button_settings: function() { |
|||
this.do_action({ |
|||
type: 'ir.actions.act_window', |
|||
res_model: "mail.channel", |
|||
res_id: this.channel.id, |
|||
views: [[false, 'form']], |
|||
target: 'current' |
|||
}); |
|||
}, |
|||
on_click_new_message: function () { |
|||
this.do_action({ |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'mail.compose.message', |
|||
view_mode: 'form', |
|||
view_type: 'form', |
|||
views: [[false, 'form']], |
|||
target: 'new', |
|||
context: "{'default_no_auto_thread': False, 'active_model': 'mail.message'}", |
|||
}); |
|||
}, |
|||
destroy: function() { |
|||
this.$buttons.off().destroy(); |
|||
this._super.apply(this, arguments); |
|||
}, |
|||
}); |
|||
|
|||
|
|||
core.action_registry.add('mail.chat.instant_messaging', ChatAction); |
|||
|
|||
}); |
@ -0,0 +1,19 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<templates id="template" xml:space="preserve"> |
|||
|
|||
<t t-extend="mail.chat.Sidebar"> |
|||
<t t-jquery="div.o_mail_chat_sidebar" t-operation="prepend"> |
|||
<div t-attf-class="o_mail_chat_channel_item #{(active_channel_id == 'channel_sent') ? 'o_active': ''}" |
|||
data-channel-id="channel_sent"> |
|||
<span class="o_channel_name"> <i class="fa fa-envelope-o"/> Sent </span> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
|
|||
<t t-extend="mail.chat.ControlButtons"> |
|||
<t t-jquery="button.o_mail_chat_button_new_message" t-operation="before"> |
|||
<button type="button" class="btn btn-primary btn-sm o_mail_chat_button_new_message_sent" title="Compose new messages">Send mails</button> |
|||
</t> |
|||
</t> |
|||
|
|||
</templates> |
@ -0,0 +1,27 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<openerp> |
|||
<data> |
|||
<template id="mail.assets_backend" name="mail assets" inherit_id="web.assets_backend"> |
|||
<xpath expr="." position="inside"> |
|||
<script type="text/javascript" src="/mail/static/src/js/many2many_tags_email.js"></script> |
|||
<script type="text/javascript" src="/mail/static/src/js/announcement.js"></script> |
|||
|
|||
<script type="text/javascript" src="/sent_mails/static/src/js/client_action_sent_mail.js"></script> |
|||
<script type="text/javascript" src="/mail/static/src/js/chat_window.js"></script> |
|||
<script type="text/javascript" src="/mail/static/src/js/composer.js"></script> |
|||
<script type="text/javascript" src="/sent_mails/static/src/js/chat_manager_sent_mail.js"></script> |
|||
<script type="text/javascript" src="/mail/static/src/js/chatter.js"></script> |
|||
<script type="text/javascript" src="/mail/static/src/js/thread.js"></script> |
|||
<script type="text/javascript" src="/mail/static/src/js/systray.js"></script> |
|||
<script type="text/javascript" src="/mail/static/src/js/window_manager.js"></script> |
|||
|
|||
<link rel="stylesheet" href="/mail/static/src/less/announcement.less"/> |
|||
<link rel="stylesheet" href="/mail/static/src/less/client_action.less" type="text/less"/> |
|||
<link rel="stylesheet" href="/mail/static/src/less/chat_window.less" type="text/less"/> |
|||
<link rel="stylesheet" href="/mail/static/src/less/composer.less" type="text/less"/> |
|||
<link rel="stylesheet" href="/mail/static/src/less/chatter.less" type="text/less"/> |
|||
<link rel="stylesheet" href="/mail/static/src/less/thread.less" type="text/less"/> |
|||
</xpath> |
|||
</template> |
|||
</data> |
|||
</openerp> |
Loading…
Reference in new issue