Browse Source
Merge pull request #114 from x620/mail-addons-8.0-mail_private
Merge pull request #114 from x620/mail-addons-8.0-mail_private
[ADD] mail_privatepull/50/head
Ivan Yelizariev
8 years ago
committed by
GitHub
10 changed files with 350 additions and 0 deletions
-
29mail_private/README.rst
-
3mail_private/__init__.py
-
35mail_private/__openerp__.py
-
7mail_private/doc/changelog.rst
-
30mail_private/doc/index.rst
-
13mail_private/models.py
-
183mail_private/static/src/js/mail_private.js
-
8mail_private/static/src/xml/mail_private.xml
-
15mail_private/template.xml
-
27mail_private/view.xml
@ -0,0 +1,29 @@ |
|||||
|
==================== |
||||
|
Internal Messaging |
||||
|
==================== |
||||
|
|
||||
|
При отправке сообщения в карточке сообщение по умолчанию отправляется всем подписанным пользователям. Но часто бывают случаи, когда отправлять сообщения нужно только определенным лицам. Данный модуль дает возможность выбирать получателей отпрвляемого сообщения и не рассылать его всем подписанным пользователям. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
* Pavel Romanchenko <romanchenko@it-projects.info> |
||||
|
|
||||
|
Sponsors |
||||
|
-------- |
||||
|
* `IT-Projects LLC <https://it-projects.info>`_ |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
|
||||
|
Demo: http://runbot.it-projects.info/demo/mail-addons/8.0 |
||||
|
|
||||
|
HTML Description: https://apps.odoo.com/apps/modules/8.0/mail_private/ |
||||
|
|
||||
|
Usage instructions: `<doc/index.rst>`_ |
||||
|
|
||||
|
Changelog: `<doc/changelog.rst>`_ |
||||
|
|
||||
|
Tested on Odoo 8.0 0af32f3f84bae07b11abb8538d02e35c7369a348 |
@ -0,0 +1,3 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
import models |
@ -0,0 +1,35 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
{ |
||||
|
"name": """Internal Messaging""", |
||||
|
"summary": """Allows you to send private messages to specified recipients only no matter who are in followers list.""", |
||||
|
"category": "Social Network", |
||||
|
"images": [], |
||||
|
"version": "1.0.0", |
||||
|
"application": False, |
||||
|
|
||||
|
"author": "IT-Projects LLC, Pavel Romanchenko", |
||||
|
"website": "https://it-projects.info", |
||||
|
"license": "GPL-3", |
||||
|
#"price": 9.00, |
||||
|
#"currency": "EUR", |
||||
|
|
||||
|
"depends": [ |
||||
|
"mail", |
||||
|
], |
||||
|
"external_dependencies": {"python": [], "bin": []}, |
||||
|
"data": [ |
||||
|
'template.xml', |
||||
|
'view.xml', |
||||
|
], |
||||
|
"qweb": [ |
||||
|
'static/src/xml/mail_private.xml', |
||||
|
], |
||||
|
"demo": [], |
||||
|
|
||||
|
"post_load": None, |
||||
|
"pre_init_hook": None, |
||||
|
"post_init_hook": None, |
||||
|
|
||||
|
"auto_install": False, |
||||
|
"installable": True, |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
Changelog |
||||
|
========= |
||||
|
|
||||
|
`1.0.0` |
||||
|
------- |
||||
|
|
||||
|
- Init version |
@ -0,0 +1,30 @@ |
|||||
|
==================== |
||||
|
Internal Messaging |
||||
|
==================== |
||||
|
|
||||
|
Installation |
||||
|
============ |
||||
|
|
||||
|
Nothing special is needed to install this module. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
Для того чтобы отправить сообщение только выбранным получателям: |
||||
|
|
||||
|
* Кликните по кнопке ``[Send Private Message]`` |
||||
|
|
||||
|
* По умолчанию все подписанные пользователи отключены. Включите флажки тем пользователям, которым вы хотите отправить сообщение. |
||||
|
|
||||
|
* Если вы хотите добавить получателей из числа неподписанных пользователей, нажмите на кнопку ``[Open the full mail composer]`` в правом верхнем углу блока отправки сообщения. |
||||
|
|
||||
|
* В поле **Recipient** добавьте получателей. |
||||
|
|
||||
|
* Нажмите кнопку ``[Send]``. |
||||
|
|
||||
|
Для проверки подпишите на какую-нибудь карточку двух получателей: Demo User и любого другого. Отправьте сообщение, выбрав в числе получателей только второго подписанного пользователя. Залогиньтесь как Demo User и проверьте, что ему сообщение не пришло. |
||||
|
|
||||
|
Uninstallation |
||||
|
============== |
||||
|
|
||||
|
Nothing special is needed to uninstall this module. |
@ -0,0 +1,13 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from openerp import api |
||||
|
from openerp.osv import osv, fields |
||||
|
from openerp import SUPERUSER_ID |
||||
|
|
||||
|
|
||||
|
class mail_compose_message(osv.TransientModel): |
||||
|
_inherit = 'mail.compose.message' |
||||
|
|
||||
|
_columns = { |
||||
|
'private': fields.boolean('Send Internal Message'), |
||||
|
} |
@ -0,0 +1,183 @@ |
|||||
|
openerp.mail_private = function(instance){ |
||||
|
|
||||
|
var mail = instance.mail; |
||||
|
|
||||
|
instance.mail.ThreadComposeMessage.include({ |
||||
|
init: function (parent, datasets, options) { |
||||
|
this._super.apply(this, arguments); |
||||
|
this.private = false; |
||||
|
}, |
||||
|
bind_events: function(){ |
||||
|
var self = this; |
||||
|
this.$('.oe_compose_post_private').on('click', self.on_toggle_quick_composer_private); |
||||
|
this._super.apply(this, arguments); |
||||
|
}, |
||||
|
on_compose_fullmail: function (default_composition_mode) { |
||||
|
var self = this; |
||||
|
if(!this.do_check_attachment_upload()) { |
||||
|
return false; |
||||
|
} |
||||
|
var recipient_done = $.Deferred(); |
||||
|
if (this.is_log) { |
||||
|
recipient_done.resolve([]); |
||||
|
} |
||||
|
else { |
||||
|
recipient_done = this.check_recipient_partners(); |
||||
|
} |
||||
|
$.when(recipient_done).done(function (partner_ids) { |
||||
|
var context = { |
||||
|
'default_parent_id': self.id, |
||||
|
'default_body': mail.ChatterUtils.get_text2html(self.$el ? (self.$el.find('textarea:not(.oe_compact)').val() || '') : ''), |
||||
|
'default_attachment_ids': _.map(self.attachment_ids, function (file) {return file.id;}), |
||||
|
'default_partner_ids': partner_ids, |
||||
|
'default_is_log': self.is_log, |
||||
|
'default_private': self.private, |
||||
|
'mail_post_autofollow': true, |
||||
|
'mail_post_autofollow_partner_ids': partner_ids, |
||||
|
'is_private': self.is_private |
||||
|
}; |
||||
|
if (default_composition_mode != 'reply' && self.context.default_model && self.context.default_res_id) { |
||||
|
context.default_model = self.context.default_model; |
||||
|
context.default_res_id = self.context.default_res_id; |
||||
|
} |
||||
|
|
||||
|
var action = { |
||||
|
type: 'ir.actions.act_window', |
||||
|
res_model: 'mail.compose.message', |
||||
|
view_mode: 'form', |
||||
|
view_type: 'form', |
||||
|
views: [[false, 'form']], |
||||
|
target: 'new', |
||||
|
context: context, |
||||
|
}; |
||||
|
|
||||
|
self.do_action(action, { |
||||
|
'on_close': function(){ !self.parent_thread.options.view_inbox && self.parent_thread.message_fetch() } |
||||
|
}); |
||||
|
self.on_cancel(); |
||||
|
}); |
||||
|
|
||||
|
}, |
||||
|
do_send_message_post: function (partner_ids, log) { |
||||
|
var self = this; |
||||
|
var values = { |
||||
|
'body': this.$('textarea').val(), |
||||
|
'subject': false, |
||||
|
'parent_id': this.context.default_parent_id, |
||||
|
'attachment_ids': _.map(this.attachment_ids, function (file) {return file.id;}), |
||||
|
'partner_ids': partner_ids, |
||||
|
'context': _.extend(this.parent_thread.context, { |
||||
|
'mail_post_autofollow': true, |
||||
|
'mail_post_autofollow_partner_ids': partner_ids, |
||||
|
'default_private': self.private |
||||
|
}), |
||||
|
'type': 'comment', |
||||
|
'content_subtype': 'plaintext', |
||||
|
}; |
||||
|
if (log || self.private) { |
||||
|
values['subtype'] = false; |
||||
|
} |
||||
|
else { |
||||
|
values['subtype'] = 'mail.mt_comment'; |
||||
|
} |
||||
|
this.parent_thread.ds_thread._model.call('message_post', [this.context.default_res_id], values).done(function (message_id) { |
||||
|
var thread = self.parent_thread; |
||||
|
var root = thread == self.options.root_thread; |
||||
|
if (self.options.display_indented_thread < self.thread_level && thread.parent_message) { |
||||
|
var thread = thread.parent_message.parent_thread; |
||||
|
} |
||||
|
// create object and attach to the thread object
|
||||
|
thread.message_fetch([["id", "=", message_id]], false, [message_id], function (arg, data) { |
||||
|
var message = thread.create_message_object( data.slice(-1)[0] ); |
||||
|
// insert the message on dom
|
||||
|
thread.insert_message( message, root ? undefined : self.$el, root ); |
||||
|
}); |
||||
|
self.on_cancel(); |
||||
|
self.flag_post = false; |
||||
|
}); |
||||
|
}, |
||||
|
on_toggle_quick_composer: function (event) { |
||||
|
if (event.target.className == 'oe_compose_post') { |
||||
|
this.recipients = []; |
||||
|
this.private = false; |
||||
|
} |
||||
|
this._super.apply(this, arguments); |
||||
|
}, |
||||
|
on_toggle_quick_composer_private: function (event) { |
||||
|
var self = this; |
||||
|
var $input = $(event.target); |
||||
|
this.compute_emails_from(); |
||||
|
var email_addresses = _.pluck(this.recipients, 'email_address'); |
||||
|
var suggested_partners = $.Deferred(); |
||||
|
|
||||
|
// if clicked: call for suggested recipients
|
||||
|
if (event.type == 'click') { |
||||
|
this.private = $input.hasClass('oe_compose_post_private'); |
||||
|
this.is_log = false; |
||||
|
suggested_partners = this.parent_thread.get_recipients_for_internal_message([this.context.default_res_id], this.context) |
||||
|
.done(function (additional_recipients) { |
||||
|
var thread_recipients = additional_recipients[self.context.default_res_id]; |
||||
|
_.each(thread_recipients, function (recipient) { |
||||
|
var parsed_email = mail.ChatterUtils.parse_email(recipient[1]); |
||||
|
if (_.indexOf(email_addresses, parsed_email[1]) == -1) { |
||||
|
self.recipients.push({ |
||||
|
'checked': false, |
||||
|
'partner_id': recipient[0], |
||||
|
'full_name': recipient[1], |
||||
|
'name': parsed_email[0], |
||||
|
'email_address': parsed_email[1], |
||||
|
'reason': recipient[2], |
||||
|
}) |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
else { |
||||
|
suggested_partners.resolve({}); |
||||
|
} |
||||
|
|
||||
|
// when call for suggested partners finished: re-render the widget
|
||||
|
$.when(suggested_partners).pipe(function (additional_recipients) { |
||||
|
if ((!self.stay_open || (event && event.type == 'click')) && (!self.show_composer || !self.$('textarea:not(.oe_compact)').val().match(/\S+/) && !self.attachment_ids.length)) { |
||||
|
self.show_composer = !self.show_composer || self.stay_open; |
||||
|
self.reinit(); |
||||
|
} |
||||
|
if (!self.stay_open && self.show_composer && (!event || event.type != 'blur')) { |
||||
|
self.$('textarea:not(.oe_compact):first').focus(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
return suggested_partners; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
instance.mail.Thread.include({ |
||||
|
get_recipients_for_internal_message: function(ids, context){ |
||||
|
var self = this; |
||||
|
self.result = {}; |
||||
|
return new instance.web.Model(context.default_model).call( |
||||
|
'read', [ids, ['message_follower_ids'], context] |
||||
|
).then(function (thread) { |
||||
|
for (var i = 0; i < thread.length; i++) { |
||||
|
var res_id = thread[i].id; |
||||
|
var followers = thread[i].message_follower_ids; |
||||
|
self.result[res_id] = []; |
||||
|
return new instance.web.Model('res.partner').call( |
||||
|
'read', [followers, ['name', 'email', 'user_ids']] |
||||
|
).then(function (res_partners){ |
||||
|
for (var j = 0; j < res_partners.length; j++) { |
||||
|
if (!_.include(res_partners[j].user_ids, self.session.uid)){ |
||||
|
var partner = res_partners[j]; |
||||
|
self.result[res_id].push( |
||||
|
[partner.id, partner.name + '<' + partner.email + '>'] |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
return self.result; |
||||
|
}); |
||||
|
} |
||||
|
return self.result; |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}; |
@ -0,0 +1,8 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<template> |
||||
|
<t t-extend="mail.compose_message"> |
||||
|
<t t-jquery="a[title='Send a message to all followers of the document']" t-operation="after"> |
||||
|
<span class="oe_grey oe_sep_word">or</span><a class="oe_compose_post_private" t-if="!widget.options.compose_placeholder and !widget.options.view_mailbox" title="Send a message to all followers of the document">Send internal message</a> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
@ -0,0 +1,15 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<template |
||||
|
id="assets_backend" |
||||
|
name="mail_private_assets_backend" |
||||
|
inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script |
||||
|
type="text/javascript" |
||||
|
src="/mail_private/static/src/js/mail_private.js"></script> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,27 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record id="mail_private_email_compose_message_wizard_form" model="ir.ui.view"> |
||||
|
<field name="name">mail.private.mail.compose.message.form</field> |
||||
|
<field name="model">mail.compose.message</field> |
||||
|
<field name="inherit_id" ref="mail.email_compose_message_wizard_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//div[@groups='base.group_user']" position="replace"> |
||||
|
<div groups="base.group_user" attrs="{'invisible': [('is_log', '=', True)]}"> |
||||
|
<field name="private" invisible="1"/> |
||||
|
<!--<field name="private"/>--> |
||||
|
<span attrs="{'invisible': [('composition_mode', '!=', 'mass_mail')]}"> |
||||
|
<strong>Email mass mailing</strong> on |
||||
|
<span attrs="{'invisible': [('use_active_domain', '=', True)]}">the selected records</span> |
||||
|
<span attrs="{'invisible': [('use_active_domain', '=', False)]}">the current search filter</span>. |
||||
|
</span> |
||||
|
<span attrs="{'invisible':['|', ('composition_mode', '!=', 'comment'), ('private', '=', True)]}">Followers of the document and</span> |
||||
|
<field name="partner_ids" widget="many2many_tags_email" placeholder="Add contacts to notify..." |
||||
|
context="{'force_email':True, 'show_email':True}" |
||||
|
attrs="{'invisible': [('composition_mode', '!=', 'comment')]}"/> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue