Browse Source

🚑 mail_private: fixing errors

pull/235/head
ommo73 5 years ago
parent
commit
2d3c71069b
No known key found for this signature in database GPG Key ID: E7E1F5C23505AFF8
  1. 2
      mail_private/__manifest__.py
  2. 5
      mail_private/doc/changelog.rst
  3. 52
      mail_private/models.py
  4. 10
      mail_private/static/src/css/mail_private.css
  5. 78
      mail_private/static/src/js/mail_private.js
  6. 9
      mail_private/static/src/xml/mail_private.xml
  7. 1
      mail_private/template.xml

2
mail_private/__manifest__.py

@ -11,7 +11,7 @@
"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": "11.0.1.1.0",
"version": "11.0.1.2.0",
"application": False, "application": False,
"author": "IT-Projects LLC, Pavel Romanchenko", "author": "IT-Projects LLC, Pavel Romanchenko",

5
mail_private/doc/changelog.rst

@ -1,3 +1,8 @@
`1.2.0`
-------
- **New**: added ability to select channels for private message sending.
`1.1.0` `1.1.0`
------- -------

52
mail_private/models.py

@ -19,17 +19,16 @@ class MailMessage(models.Model):
is_private = fields.Boolean(string='Send Internal Message') is_private = fields.Boolean(string='Send Internal Message')
def send_recepients_for_internal_message(self, model, domain): def send_recepients_for_internal_message(self, model, domain):
result = []
result = {'partners': [], 'channels': []}
default_resource = self.env[model].search(domain) default_resource = self.env[model].search(domain)
follower_ids = default_resource.message_follower_ids follower_ids = default_resource.message_follower_ids
internal_ids = self.get_internal_users_ids()
recipient_ids = [r.partner_id for r in follower_ids if r.partner_id] recipient_ids = [r.partner_id for r in follower_ids if r.partner_id]
# channel_ids = [c.channel_id for c in follower_ids if c.channel_id]
channel_ids = [c.channel_id for c in follower_ids if c.channel_id]
for recipient in recipient_ids: for recipient in recipient_ids:
result.append({
'checked': recipient.user_ids.id in internal_ids,
result['partners'].append({
'checked': recipient.user_ids.id and not any(recipient.user_ids.mapped('share')),
'partner_id': recipient.id, 'partner_id': recipient.id,
'full_name': recipient.name, 'full_name': recipient.name,
'name': recipient.name, 'name': recipient.name,
@ -37,14 +36,14 @@ class MailMessage(models.Model):
'reason': 'Recipient' 'reason': 'Recipient'
}) })
# for channel in channel_ids:
# result.append({
# 'checked': True,
# 'channel_id': channel.id,
# 'full_name': channel,
# 'name': '# '+channel.name,
# 'reason': 'Channel',
# })
for channel in channel_ids:
result['channels'].append({
'checked': True,
'channel_id': channel.id,
'full_name': channel.name,
'name': '# '+channel.name,
'reason': 'Channel',
})
return result return result
@api.multi @api.multi
@ -60,7 +59,6 @@ class MailMessage(models.Model):
""" Compute recipients to notify based on specified recipients and document """ Compute recipients to notify based on specified recipients and document
followers. Delegate notification to partners to send emails and bus notifications followers. Delegate notification to partners to send emails and bus notifications
and to channels to broadcast messages on channels """ and to channels to broadcast messages on channels """
group_user = self.env.ref('base.group_user')
# have a sudoed copy to manipulate partners (public can go here with website modules like forum / blog / ... ) # have a sudoed copy to manipulate partners (public can go here with website modules like forum / blog / ... )
self_sudo = self.sudo() self_sudo = self.sudo()
@ -68,16 +66,6 @@ class MailMessage(models.Model):
partners_sudo = self_sudo.partner_ids partners_sudo = self_sudo.partner_ids
channels_sudo = self_sudo.channel_ids channels_sudo = self_sudo.channel_ids
if self_sudo.subtype_id and self.model and self.res_id:
followers = self_sudo.env['mail.followers'].search([
('res_model', '=', self.model),
('res_id', '=', self.res_id),
('subtype_ids', 'in', self_sudo.subtype_id.id),
])
if self_sudo.subtype_id.internal:
followers = followers.filtered(lambda fol: fol.channel_id or (fol.partner_id.user_ids and group_user in fol.partner_id.user_ids[0].mapped('groups_id')))
channels_sudo |= followers.mapped('channel_id')
# remove author from notified partners # remove author from notified partners
if not self._context.get('mail_notify_author', False) and self_sudo.author_id: if not self._context.get('mail_notify_author', False) and self_sudo.author_id:
partners_sudo = partners_sudo - self_sudo.author_id partners_sudo = partners_sudo - self_sudo.author_id
@ -114,6 +102,16 @@ class MailMessage(models.Model):
return True return True
def get_internal_users_ids(self):
internal_users_ids = self.env['res.users'].search([('share', '=', False)]).ids
return internal_users_ids
class MailThread(models.AbstractModel):
_inherit = 'mail.thread'
@api.multi
@api.returns('self', lambda value: value.id)
def message_post(self, body='', subject=None, message_type='notification', subtype=None, parent_id=False,
attachments=None, content_subtype='html', **kwargs):
if 'channel_ids' in kwargs:
kwargs['channel_ids'] = [(4, pid) for pid in kwargs['channel_ids']]
return super(MailThread, self).message_post(body, subject, message_type,
subtype, parent_id, attachments,
content_subtype, **kwargs)

10
mail_private/static/src/css/mail_private.css

@ -0,0 +1,10 @@
.o_composer_suggested_channels{
margin-top: -5px;
}
.oe_composer_uncheck{
float: bottom;
margin-top:5px;
margin-left:-5px;
}

78
mail_private/static/src/js/mail_private.js

@ -30,7 +30,8 @@ Chatter.include({
this.fetch_recipients_for_internal_message().then(function (data) { this.fetch_recipients_for_internal_message().then(function (data) {
self._openComposer({ self._openComposer({
is_private: true, is_private: true,
suggested_partners: data
suggested_partners: data["partners"],
suggested_channels: data["channels"],
}); });
}); });
}, },
@ -49,7 +50,8 @@ Chatter.include({
record_name: this.record_name, record_name: this.record_name,
default_body: old_composer && old_composer.$input && old_composer.$input.val(), default_body: old_composer && old_composer.$input && old_composer.$input.val(),
default_mention_selections: old_composer && old_composer.mention_get_listener_selections(), default_mention_selections: old_composer && old_composer.mention_get_listener_selections(),
is_private: options.is_private
is_private: options.is_private,
suggested_channels: options.suggested_channels
}); });
this.composer.on('input_focused', this, function () { this.composer.on('input_focused', this, function () {
this.composer.mention_set_prefetched_partners(this.mentionSuggestions || []); this.composer.mention_set_prefetched_partners(this.mentionSuggestions || []);
@ -65,6 +67,7 @@ Chatter.include({
self.composer.on('post_message', self, function (message) { self.composer.on('post_message', self, function (message) {
if (options.is_private) { if (options.is_private) {
self.composer.options.is_log = true; self.composer.options.is_log = true;
self.composer.options.is_private = options.is_private;
} }
self.fields.thread.postMessage(message).then(function () { self.fields.thread.postMessage(message).then(function () {
@ -95,70 +98,18 @@ Chatter.include({
method: 'send_recepients_for_internal_message', method: 'send_recepients_for_internal_message',
args: [[], self.context.default_model, follower_ids_domain] args: [[], self.context.default_model, follower_ids_domain]
}).then(function (res) { }).then(function (res) {
return _.filter(res, function (obj) {
res["partners"] = _.filter(res["partners"], function (obj) {
return obj.partner_id !== session.partner_id; return obj.partner_id !== session.partner_id;
}); });
return res;
}); });
}, },
get_channels_for_internal_message: function () {
var self = this;
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 channels ids
return new Model('mail.followers').call(
'read', [follower_ids, ['channel_id']]).then(function (res_channels) {
// Filter result and push to array
var res_channels_filtered = _.map(res_channels, function (channel) {
if (channel.channel_id[0]) {
return channel.channel_id[0];
}
}).filter(function (channel) {
return typeof channel !== 'undefined';
});
return new Model('mail.channel').call(
'read', [res_channels_filtered, ['name', 'id']]
).then(function (recipients) {
return recipients;
});
});
});
},
get_internal_users_ids: function () {
var ResUser = new Model('mail.compose.message');
this.users_ids = ResUser.call('get_internal_users_ids', [[]]).then( function (users_ids) {
return users_ids;
});
return this.users_ids;
},
get_checked_channels_ids: function () {
var self = this;
var checked_channels = [];
this.$('.o_composer_suggested_channels input:checked').each(function() {
var full_name = $(this).data('fullname').toString();
_.each(self.channels_for_internal_message, function(item) {
if (full_name === item.name) {
checked_channels.push(item.id);
}
});
});
return checked_channels;
},
}); });
ChatterComposer.include({ ChatterComposer.include({
init: function (parent, model, suggested_partners, options) { init: function (parent, model, suggested_partners, options) {
this._super(parent, model, suggested_partners, options); this._super(parent, model, suggested_partners, options);
this.suggested_channels = options.suggested_channels;
this.events['click .oe_composer_uncheck'] = 'on_uncheck_recipients'; this.events['click .oe_composer_uncheck'] = 'on_uncheck_recipients';
if (typeof options.is_private === 'undefined') { if (typeof options.is_private === 'undefined') {
// otherwise it causes an error in context creating function // otherwise it causes an error in context creating function
@ -214,14 +165,6 @@ ChatterComposer.include({
}); });
}, },
preprocess_message: function () {
var self = this;
if (self.options.is_private) {
self.context.is_private = true;
}
return this._super();
},
on_open_full_composer: function() { on_open_full_composer: function() {
if (!this.do_check_attachment_upload()){ if (!this.do_check_attachment_upload()){
return false; return false;
@ -281,16 +224,15 @@ ChatterComposer.include({
checked_partners = _.uniq(_.filter(checked_partners, function (obj) { checked_partners = _.uniq(_.filter(checked_partners, function (obj) {
return obj.reason !== 'Channel'; return obj.reason !== 'Channel';
})); }));
this.get_checked_channel_ids();
return checked_partners; return checked_partners;
}, },
get_checked_channel_ids: function () { get_checked_channel_ids: function () {
var self = this; var self = this;
var checked_channels = []; var checked_channels = [];
this.$('.o_composer_suggested_partners input:checked').each(function() {
this.$('.o_composer_suggested_channels input:checked').each(function() {
var full_name = $(this).data('fullname'); var full_name = $(this).data('fullname');
checked_channels = checked_channels.concat(_.filter(self.suggested_partners, function(item) {
checked_channels = checked_channels.concat(_.filter(self.suggested_channels, function(item) {
return full_name === item.full_name; return full_name === item.full_name;
})); }));
}); });

9
mail_private/static/src/xml/mail_private.xml

@ -9,7 +9,7 @@
<t t-extend="mail.Chatter.Buttons"> <t t-extend="mail.Chatter.Buttons">
<t t-jquery="button[title='Send a message']" t-operation="after"> <t t-jquery="button[title='Send a message']" t-operation="after">
<button class="btn btn-sm btn-link oe_compose_post_private" title="Send a message to specified recipients only">Send internal message</button>
<button t-if="new_message_btn" class="btn btn-sm btn-link oe_compose_post_private" title="Send a message to specified recipients only">Send internal message</button>
</t> </t>
</t> </t>
@ -27,16 +27,21 @@
</t> </t>
<t t-jquery="div[class='o_composer_suggested_partners']" t-operation="after"> <t t-jquery="div[class='o_composer_suggested_partners']" t-operation="after">
<div class="o_composer_suggested_channels"> <div class="o_composer_suggested_channels">
<t t-if="widget.suggested_channels">
<t t-foreach='widget.suggested_channels' t-as='channel'> <t t-foreach='widget.suggested_channels' t-as='channel'>
<div t-attf-title="Add as channel and follower"> <div t-attf-title="Add as channel and follower">
<div class="o_checkbox">
<input type="checkbox" <input type="checkbox"
t-att-checked="channel.checked ? 'checked' : undefined" t-att-checked="channel.checked ? 'checked' : undefined"
t-att-data-fullname="channel.full_name"/> t-att-data-fullname="channel.full_name"/>
<span/>
</div>
<t t-esc="channel.name"/> <t t-esc="channel.name"/>
</div> </div>
</t> </t>
</div>
</t>
<button class="btn btn-sm btn-link oe_composer_uncheck" t-if="widget.options.is_private">Uncheck all</button> <button class="btn btn-sm btn-link oe_composer_uncheck" t-if="widget.options.is_private">Uncheck all</button>
</div>
</t> </t>
</t> </t>

1
mail_private/template.xml

@ -7,6 +7,7 @@
name="mail_private_assets_backend" name="mail_private_assets_backend"
inherit_id="web.assets_backend"> inherit_id="web.assets_backend">
<xpath expr="." position="inside"> <xpath expr="." position="inside">
<link rel="stylesheet" href="/mail_private/static/src/css/mail_private.css"/>
<script <script
type="text/javascript" type="text/javascript"
src="/mail_private/static/src/js/mail_private.js"></script> src="/mail_private/static/src/js/mail_private.js"></script>

Loading…
Cancel
Save