Browse Source

Merge pull request #105 from ArtyomLosev/9.0-mail_private

[PORT] mail_private for odoo 9.0
pull/117/merge
ILMIR 7 years ago
committed by GitHub
parent
commit
4a2906b290
  1. 6
      mail_private/README.rst
  2. 6
      mail_private/__openerp__.py
  3. 6
      mail_private/doc/changelog.rst
  4. 8
      mail_private/models.py
  5. 257
      mail_private/static/src/js/mail_private.js
  6. 8
      mail_private/static/src/xml/mail_private.xml
  7. 27
      mail_private/view.xml

6
mail_private/README.rst

@ -18,12 +18,12 @@ Sponsors
Further information Further information
=================== ===================
Demo: http://runbot.it-projects.info/demo/mail-addons/8.0
Demo: http://runbot.it-projects.info/demo/mail-addons/9.0
HTML Description: https://apps.odoo.com/apps/modules/8.0/mail_private/
HTML Description: https://apps.odoo.com/apps/modules/9.0/mail_private/
Usage instructions: `<doc/index.rst>`__ Usage instructions: `<doc/index.rst>`__
Changelog: `<doc/changelog.rst>`__ Changelog: `<doc/changelog.rst>`__
Tested on Odoo 8.0 0af32f3f84bae07b11abb8538d02e35c7369a348
Tested on Odoo 9.0 d612daae719ce3da86c3e44a91a6138a1733dcc2

6
mail_private/__openerp__.py

@ -4,10 +4,11 @@
"summary": """Send private messages to specified recipients, regardless of who are in followers list.""", "summary": """Send private messages to specified recipients, regardless of who are in followers list.""",
"category": "Discuss", "category": "Discuss",
"images": ['images/mail_private_image.png'], "images": ['images/mail_private_image.png'],
"version": "1.0.0",
"version": "1.0.1",
"application": False, "application": False,
"author": "IT-Projects LLC, Pavel Romanchenko", "author": "IT-Projects LLC, Pavel Romanchenko",
"support": "apps@it-projects.info",
"website": "https://it-projects.info", "website": "https://it-projects.info",
"license": "GPL-3", "license": "GPL-3",
"price": 50.00, "price": 50.00,
@ -19,7 +20,6 @@
"external_dependencies": {"python": [], "bin": []}, "external_dependencies": {"python": [], "bin": []},
"data": [ "data": [
'template.xml', 'template.xml',
'view.xml',
], ],
"qweb": [ "qweb": [
'static/src/xml/mail_private.xml', 'static/src/xml/mail_private.xml',
@ -31,5 +31,5 @@
"post_init_hook": None, "post_init_hook": None,
"auto_install": False, "auto_install": False,
"installable": False,
"installable": True,
} }

6
mail_private/doc/changelog.rst

@ -1,5 +1,7 @@
Updates
=======
`1.0.1`
-------
- **PORT:** Odoo 9 support.
`1.0.0` `1.0.0`
------- -------

8
mail_private/models.py

@ -1,11 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from openerp.osv import osv, fields
from openerp import models, fields
class MailComposeMessage(osv.TransientModel):
class MailComposeMessage(models.TransientModel):
_inherit = 'mail.compose.message' _inherit = 'mail.compose.message'
_columns = {
'private': fields.boolean('Send Internal Message'),
}
private = fields.Boolean(string='Send Internal Message')

257
mail_private/static/src/js/mail_private.js

@ -1,201 +1,100 @@
openerp.mail_private = function(instance){
odoo.define('mail_private', function (require) {
'use strict';
var mail = instance.mail;
var core = require('web.core');
var Chatter = require('mail.Chatter');
var chat_manager = require('mail.chat_manager');
var session = require('web.session');
var Model = require('web.Model');
instance.mail.ThreadComposeMessage.include({
init: function (parent, datasets, options) {
Chatter.include({
init: function () {
this._super.apply(this, arguments); this._super.apply(this, arguments);
this.private = false; this.private = false;
this.events['click .oe_compose_post_private'] = 'on_open_composer_private_message';
}, },
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();
on_post_message: function (message) {
var self = this;
if (this.private) {
message.subtype = false;
}
var options = {model: this.model, res_id: this.res_id};
chat_manager.post_message(message, options).then(
function () {
self.close_composer();
if (message.partner_ids.length) {
self.refresh_followers();
}
}).fail(function () {
// todo: display notification
}); });
},
},
do_send_message_post: function (partner_ids, log) {
on_open_composer_private_message: function (event) {
var self = this; 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;
this.private = true;
this.get_recipients_for_internal_message().then(function (data) {
var private_message = 'private_message';
self.recipients_for_internal_message = data;
self.open_composer(private_message);
}); });
}, },
on_toggle_quick_composer: function (event) {
if (event.target.className == 'oe_compose_post') {
this.recipients = [];
this.private = false;
}
on_open_composer_new_message: function () {
this._super.apply(this, arguments); this._super.apply(this, arguments);
this.private = false;
}, },
on_toggle_quick_composer_private: function (event) {
this.recipients = [];
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],
});
}
});
open_composer: function (options) {
var self = this;
this._super.apply(this, arguments);
if (options === 'private_message') {
//Clear existing suggested partners
for (var i=0; i<self.recipients_for_internal_message.length; i++) {
this.composer.suggested_partners.push({
checked: true,
partner_id: self.recipients_for_internal_message[i].id,
full_name: self.recipients_for_internal_message[i].name,
name: self.recipients_for_internal_message[i].name,
email_address: self.recipients_for_internal_message[i].email,
reason: _.include(self.recipients_for_internal_message[i].user_ids, self.session.uid)
?'Partner'
:'Follower'
}); });
}
else {
suggested_partners.resolve({});
}
// uncheck partners from compute_emails_from
_.each(this.recipients, function(r){
if (!r.partner_id){
r.checked = false;
}
});
// 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){
get_recipients_for_internal_message: function () {
var self = this; var self = this;
self.result = {}; self.result = {};
return new instance.web.Model(context.default_model).call(
'read', [ids, ['message_follower_ids', 'partner_id'], context]
).then(function (thread) {
for (var i = 0; i < thread.length; i++) {
var res_id = thread[i].id;
var recipient_ids = thread[i].message_follower_ids;
self.result[res_id] = [];
// Add customer
self.customer = thread[i].partner_id;
if (self.customer && !recipient_ids.includes(self.customer[0])) {
recipient_ids.splice(0, 0, self.customer[0]);
}
return new instance.web.Model('res.partner').call(
'read', [recipient_ids, ['name', 'email', 'user_ids']]
).then(function (res_partners){
for (var j = 0; j < res_partners.length; j++) {
var partner = res_partners[j];
if (!_.include(partner.user_ids, self.session.uid)){
var reason = 'Follower';
if (self.customer && partner.id == self.customer[0]){
reason = 'Partner';
}
self.result[res_id].push(
[partner.id, partner.name + '<' + partner.email + '>', reason]
);
}
}
return self.result;
});
}
return self.result;
return new Model(this.context.default_model).query(
['message_follower_ids', 'partner_id']).filter(
[['id', '=', self.context.default_res_id]]).all().
then(function (thread) {
var follower_ids = thread[0].message_follower_ids;
self.result[self.context.default_res_id] = [];
self.customer = thread[0].partner_id;
// Fetch partner ids
return new Model('mail.followers').call(
'read', [follower_ids, ['partner_id']]).then(function (res_partners) {
var res_partners_filtered = [];
// Filter result and push to array
_.each(res_partners, function (partner) {
if (partner.partner_id[0] && partner.partner_id[0] !== session.partner_id ) {
res_partners_filtered.push(partner.partner_id[0]);
}
});
return new Model('res.partner').call(
'read', [res_partners_filtered, ['name', 'email', 'user_ids']]
).then(function (recipients) {
return recipients;
});
});
}); });
} }
}); });
};
});

8
mail_private/static/src/xml/mail_private.xml

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<template> <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 specified recipients only">Send internal message</a>
<t t-extend="mail.Chatter">
<t t-jquery="button[title='Send a message']" t-operation="after">
<button class="btn btn-sm btn-link oe_compose_post_private" t-if="!widget.options.compose_placeholder and !widget.options.view_mailbox" title="Send a message to specified recipients only">Send internal message</button>
</t> </t>
</t> </t>
<t t-extend="mail.thread.list_recipients">
<t t-extend="mail.chatter.ChatComposer">
<t t-jquery="[t-if='!widget.is_private']" t-operation="replace"> <t t-jquery="[t-if='!widget.is_private']" t-operation="replace">
<t t-if="!widget.is_private and !widget.private"> <t t-if="!widget.is_private and !widget.private">
<span class="oe_all_follower"> <span class="oe_all_follower">

27
mail_private/view.xml

@ -1,27 +0,0 @@
<?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>
Loading…
Cancel
Save