diff --git a/mail_private/README.rst b/mail_private/README.rst new file mode 100644 index 0000000..1bbfd6f --- /dev/null +++ b/mail_private/README.rst @@ -0,0 +1,29 @@ +==================== + Internal Messaging +==================== + +При отправке сообщения в карточке сообщение по умолчанию отправляется всем подписанным пользователям. Но часто бывают случаи, когда отправлять сообщения нужно только определенным лицам. Данный модуль дает возможность выбирать получателей отпрвляемого сообщения и не рассылать его всем подписанным пользователям. + +Credits +======= + +Contributors +------------ +* Pavel Romanchenko + +Sponsors +-------- +* `IT-Projects LLC `_ + +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: ``_ + +Changelog: ``_ + +Tested on Odoo 8.0 0af32f3f84bae07b11abb8538d02e35c7369a348 \ No newline at end of file diff --git a/mail_private/__init__.py b/mail_private/__init__.py new file mode 100644 index 0000000..c7b5ac7 --- /dev/null +++ b/mail_private/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import models diff --git a/mail_private/__openerp__.py b/mail_private/__openerp__.py new file mode 100644 index 0000000..31cfc56 --- /dev/null +++ b/mail_private/__openerp__.py @@ -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, +} diff --git a/mail_private/doc/changelog.rst b/mail_private/doc/changelog.rst new file mode 100644 index 0000000..e2b0277 --- /dev/null +++ b/mail_private/doc/changelog.rst @@ -0,0 +1,7 @@ +Changelog +========= + +`1.0.0` +------- + +- Init version diff --git a/mail_private/doc/index.rst b/mail_private/doc/index.rst new file mode 100644 index 0000000..b225f16 --- /dev/null +++ b/mail_private/doc/index.rst @@ -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. diff --git a/mail_private/models.py b/mail_private/models.py new file mode 100644 index 0000000..ce69730 --- /dev/null +++ b/mail_private/models.py @@ -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'), + } diff --git a/mail_private/static/src/js/mail_private.js b/mail_private/static/src/js/mail_private.js new file mode 100644 index 0000000..04dfed2 --- /dev/null +++ b/mail_private/static/src/js/mail_private.js @@ -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; + }); + } + }); +}; diff --git a/mail_private/static/src/xml/mail_private.xml b/mail_private/static/src/xml/mail_private.xml new file mode 100644 index 0000000..f101a06 --- /dev/null +++ b/mail_private/static/src/xml/mail_private.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/mail_private/template.xml b/mail_private/template.xml new file mode 100644 index 0000000..534e53c --- /dev/null +++ b/mail_private/template.xml @@ -0,0 +1,15 @@ + + + + + + diff --git a/mail_private/view.xml b/mail_private/view.xml new file mode 100644 index 0000000..53232fa --- /dev/null +++ b/mail_private/view.xml @@ -0,0 +1,27 @@ + + + + + mail.private.mail.compose.message.form + mail.compose.message + + + +
+ + + + Email mass mailing on + the selected records + the current search filter. + + Followers of the document and + +
+
+
+
+
+
\ No newline at end of file