diff --git a/mail_private_message/README.rst b/mail_private_message/README.rst new file mode 100644 index 00000000000..911f6ef237c --- /dev/null +++ b/mail_private_message/README.rst @@ -0,0 +1,32 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +==================== +Mail Private Message +==================== + +Features + +* Private messages visible to employees only. +* Disable notifications to followers. + +Credits +======= + +Contributors +------------ + +* Glen Sojo +* Lesmed Gutiérrez +* Antonio Hidalgo + + +Maintainer +---------- + +.. image:: https://avatars0.githubusercontent.com/u/7594691?v=3&s=200 + :alt: ClearCorp + :target: http://clearcorp.cr + +This module is maintained by ClearCorp. diff --git a/mail_private_message/__init__.py b/mail_private_message/__init__.py new file mode 100644 index 00000000000..1e285d85473 --- /dev/null +++ b/mail_private_message/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# © 2016 ClearCorp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import models +import wizard diff --git a/mail_private_message/__openerp__.py b/mail_private_message/__openerp__.py new file mode 100644 index 00000000000..5924c234dea --- /dev/null +++ b/mail_private_message/__openerp__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# © 2016 ClearCorp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + 'name': 'Mail Private Message', + 'version': '9.0.1.0', + 'category': 'Mail', + 'sequence': 10, + 'summary': """Private messages and notifications""", + 'author': 'ClearCorp', + 'website': 'http://clearcorp.cr', + 'installable': True, + 'auto_install': False, + 'application': False, + 'license': 'AGPL-3', + 'depends': ['mail', 'base'], + 'data': [ + 'views/assets_backend.xml', + 'wizard/mail_compose_view.xml', + 'security/mail_private_message_security.xml', + ], + 'qweb': ['static/src/xml/mail.xml'], +} diff --git a/mail_private_message/i18n/es.po b/mail_private_message/i18n/es.po new file mode 100644 index 00000000000..ab05fffacab --- /dev/null +++ b/mail_private_message/i18n/es.po @@ -0,0 +1,48 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mail_private_message +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-02-18 15:51+0000\n" +"PO-Revision-Date: 2016-02-18 15:51+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: mail_private_message +#: field:mail.compose.message,privacity:0 +#: field:mail.message,privacity:0 +msgid "Privacity" +msgstr "Privacidad" + +#. module: mail_private_message +#: selection:mail.compose.message,privacity:0 +#: selection:mail.message,privacity:0 +msgid "Private" +msgstr "Privado" + +#. module: mail_private_message +#: selection:mail.compose.message,privacity:0 +#: selection:mail.message,privacity:0 +msgid "Public" +msgstr "Público" + +#. module: mail_private_message +#. openerp-web +#: code:addons/mail_private_message/static/src/xml/mail.xml:15 +#, python-format +msgid "Send" +msgstr "Enviar" + +#. module: mail_private_message +#. openerp-web +#: code:addons/mail_private_message/static/src/xml/mail.xml:9 +#, python-format +msgid "Send as private" +msgstr "Enviar como privado" diff --git a/mail_private_message/i18n/mail_private_message.pot b/mail_private_message/i18n/mail_private_message.pot new file mode 100644 index 00000000000..0bf5bc4c79f --- /dev/null +++ b/mail_private_message/i18n/mail_private_message.pot @@ -0,0 +1,48 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mail_private_message +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-02-18 15:51+0000\n" +"PO-Revision-Date: 2016-02-18 15:51+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: mail_private_message +#: field:mail.compose.message,privacity:0 +#: field:mail.message,privacity:0 +msgid "Privacity" +msgstr "" + +#. module: mail_private_message +#: selection:mail.compose.message,privacity:0 +#: selection:mail.message,privacity:0 +msgid "Private" +msgstr "" + +#. module: mail_private_message +#: selection:mail.compose.message,privacity:0 +#: selection:mail.message,privacity:0 +msgid "Public" +msgstr "" + +#. module: mail_private_message +#. openerp-web +#: code:addons/mail_private_message/static/src/xml/mail.xml:15 +#, python-format +msgid "Send" +msgstr "" + +#. module: mail_private_message +#. openerp-web +#: code:addons/mail_private_message/static/src/xml/mail.xml:9 +#, python-format +msgid "Send as private" +msgstr "" diff --git a/mail_private_message/models/__init__.py b/mail_private_message/models/__init__.py new file mode 100644 index 00000000000..92ce838942b --- /dev/null +++ b/mail_private_message/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# © 2016 ClearCorp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import notification +import message diff --git a/mail_private_message/models/message.py b/mail_private_message/models/message.py new file mode 100644 index 00000000000..55ce9ef053d --- /dev/null +++ b/mail_private_message/models/message.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +# © 2016 ClearCorp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import models, fields, api + + +class MailMessage(models.Model): + + _inherit = 'mail.message' + + privacy = fields.Selection( + [('private', 'Private'), ('public', 'Public')], + 'Privacy', default='public') + + @api.model + def _notify(self, newid, force_send=False, user_signature=True): + + message = self.sudo().browse(newid) + + if message.privacy != 'private': + return super(MailMessage, self)._notify( + newid, force_send=force_send, user_signature=user_signature) + + notification_obj = self.env['mail.notification'] + partner_obj = self.env['res.partner'] + user_obj = self.pool.get('res.users') + partners_to_notify = set([]) + + # all followers of the mail.message document have to be added + # as partners and notified if a subtype is defined + # (otherwise: log message) + if message.subtype_id and message.model and message.res_id: + fol_obj = self.env['mail.followers'] + # browse as SUPERUSER because rules could + # restrict the search results + fol_ids = fol_obj.sudo().search([ + ('res_model', '=', message.model), + ('res_id', '=', message.res_id)]) + partners_to_notify |= set( + fo.partner_id.id for fo in fol_ids + if message.subtype_id.id in [st.id for st in fo.subtype_ids] + ) + + # remove current user from notified partners, unless the message + # is written on her own wall + if message.subtype_id and message.author_id and \ + message.model == 'res.partner' and \ + message.res_id == message.author_id.id: + partners_to_notify |= message.author_id.id + elif message.author_id: + partners_to_notify -= message.author_id.id + + # all partner_ids of mail.message have to be notified + # regardless of the above (even the author if explicitly added!) + if message.partner_ids: + partners_to_notify |= set([p.id for p in message.partner_ids]) + + clean_partners = [] + # clean partners to notify only internal users + for partner in partner_obj.browse(list(partners_to_notify)): + for user in partner.user_ids: + if user_obj.has_group(self._cr, user.id, 'base.group_user'): + clean_partners.append(partner.id) + + # notify + notification_obj._notify( + newid, partners_to_notify=clean_partners, + force_send=force_send, user_signature=user_signature + ) + message.refresh() + + # An error appears when a user receives a notification without + # notifying the parent message -> add a read notification for + # the parent + if message.parent_id: + # all notified_partner_ids of the mail.message have + # to be notified of the parented messages + partners_to_parent_notify = set( + message.notified_partner_ids).difference( + message.parent_id.notified_partner_ids) + for partner in partners_to_parent_notify: + for user in partner.user_ids: + if user.has_group('base.group_user'): + notification_obj.create({ + 'message_id': message.parent_id.id, + 'partner_id': partner.id, + 'is_read': True, + }) + return True diff --git a/mail_private_message/models/notification.py b/mail_private_message/models/notification.py new file mode 100644 index 00000000000..9e535c7be19 --- /dev/null +++ b/mail_private_message/models/notification.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# © 2016 ClearCorp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import models, api + + +class Notification(models.Model): + # The mail.notification class was eliminated in v9. The candidates for this + # functionality are found in res_partner, mail_channel and mail_message. + # Run new message functions to find out what is used. + _inherit = 'mail.notification' + + @api.model + def _notify(self, message_id, partners_to_notify=None, + force_send=False, user_signature=True): + if 'notify' in self.env.context and not self.env.context['notify']: + partner_obj = self.env['res.partner'] + message = self.env['mail.message'].browse(message_id) + partners_to_notify = self.env.context.get('partners_to_notify', []) + if message.privacy == 'private': + user_obj = self.pool.get('res.users') + clean_partners = [] + # clean partners to notify only internal users + for partner in partner_obj.browse(partners_to_notify): + for user in partner.user_ids: + if user_obj.has_group( + self._cr, user.id, 'base.group_user'): + clean_partners.append(partner.id) + partners_to_notify = clean_partners + else: + partners_to_notify = self.env.context.get('partners_to_notify', + partners_to_notify) + return super(Notification, self)._notify( + message_id, partners_to_notify=partners_to_notify, + force_send=force_send, user_signature=user_signature) diff --git a/mail_private_message/security/mail_private_message_security.xml b/mail_private_message/security/mail_private_message_security.xml new file mode 100644 index 00000000000..c6cedd5e70f --- /dev/null +++ b/mail_private_message/security/mail_private_message_security.xml @@ -0,0 +1,11 @@ + + + + + Portal Public Messages + + [('privacy', '=', 'public')] + + + + \ No newline at end of file diff --git a/mail_private_message/static/description/icon.png b/mail_private_message/static/description/icon.png new file mode 100644 index 00000000000..253242ee261 Binary files /dev/null and b/mail_private_message/static/description/icon.png differ diff --git a/mail_private_message/static/src/js/mail.js b/mail_private_message/static/src/js/mail.js new file mode 100644 index 00000000000..6ed1ee258dd --- /dev/null +++ b/mail_private_message/static/src/js/mail.js @@ -0,0 +1,67 @@ +openerp.mail_private_message = function(session) { + + session.mail.ThreadComposeMessage.include({ + bind_events: function () { + var self = this; + this.$('.oe_post_private').on('click', self.on_message_post_private); + this._super(); + }, + + on_message_post_private: function (event) { + var self = this; + if (self.flag_post) { + return; + } + if (this.do_check_attachment_upload() && (this.attachment_ids.length || this.$('textarea').val().match(/\S+/))) { + self.flag_post = true; + if (this.is_log) { + this.do_send_message_post([], this.is_log); + } + else { + this.check_recipient_partners().done(function (partner_ids) { + self.do_send_message_post_private(partner_ids, self.is_log); + }); + } + } + }, + + do_send_message_post_private: 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, + }), + 'type': 'comment', + 'content_subtype': 'plaintext', + 'privacy': 'private', + }; + if (log) { + 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; + }); + }, + }); +} \ No newline at end of file diff --git a/mail_private_message/static/src/xml/mail.xml b/mail_private_message/static/src/xml/mail.xml new file mode 100644 index 00000000000..8b408bbc62a --- /dev/null +++ b/mail_private_message/static/src/xml/mail.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mail_private_message/views/assets_backend.xml b/mail_private_message/views/assets_backend.xml new file mode 100644 index 00000000000..0f734eee897 --- /dev/null +++ b/mail_private_message/views/assets_backend.xml @@ -0,0 +1,10 @@ + + + +