diff --git a/mail_multi_website/doc/changelog.rst b/mail_multi_website/doc/changelog.rst
index b47d587..4a57ab7 100644
--- a/mail_multi_website/doc/changelog.rst
+++ b/mail_multi_website/doc/changelog.rst
@@ -1,7 +1,7 @@
`1.0.1`
-------
-- **Fix:** Issue related to module uninstallation
+- **Fix:** Issue with module uninstallation
`1.0.0`
-------
diff --git a/mail_private/README.rst b/mail_private/README.rst
index ea60ffe..f280cae 100644
--- a/mail_private/README.rst
+++ b/mail_private/README.rst
@@ -25,7 +25,7 @@ Maintainers
To get a guaranteed support
you are kindly requested to purchase the module
- at `odoo apps store `__.
+ at `odoo apps store `__.
Thank you for understanding!
@@ -34,14 +34,14 @@ Maintainers
Further information
===================
-Demo: http://runbot.it-projects.info/demo/mail-addons/11.0
+Demo: http://runbot.it-projects.info/demo/mail-addons/12.0
-HTML Description: https://apps.odoo.com/apps/modules/11.0/mail_private/
+HTML Description: https://apps.odoo.com/apps/modules/12.0/mail_private/
Usage instructions: ``_
Changelog: ``_
-Notifications on updates: `via Atom `_, `by Email `_
+Notifications on updates: `via Atom `_, `by Email `_
-Tested on Odoo 11.0 3d09560ffc779e169ed9488e4e07928204dd234d
+Tested on Odoo 12.0 5240bc2303816348837425b88fc7ee3ff7de2336
diff --git a/mail_private/__init__.py b/mail_private/__init__.py
index a9e3372..ea29fd5 100644
--- a/mail_private/__init__.py
+++ b/mail_private/__init__.py
@@ -1,2 +1,3 @@
+# License LGPL-3.0 (https://www.gnu.org/licenses/lgpl.html).
from . import models
diff --git a/mail_private/__manifest__.py b/mail_private/__manifest__.py
index 9ae93b5..a97ec25 100644
--- a/mail_private/__manifest__.py
+++ b/mail_private/__manifest__.py
@@ -1,37 +1,52 @@
+# Copyright 2018 Kolushov Alexandr
+# Copyright 2019 Artem Rafailov
+# License LGPL-3.0 (https://www.gnu.org/licenses/lgpl.html).
{
"name": """Internal Messaging""",
"summary": """Send private messages to specified recipients, regardless of who are in followers list.""",
"category": "Discuss",
- "images": ['images/mail_private_image.png'],
- "version": "11.0.1.0.2",
+ # "live_test_url": "http://apps.it-projects.info/shop/product/DEMO-URL?version=12.0",
+ "images": [],
+ "version": "12.0.1.0.2",
"application": False,
"author": "IT-Projects LLC, Pavel Romanchenko",
"support": "apps@it-projects.info",
- "website": "https://it-projects.info",
- "license": "GPL-3",
+ "website": "https://it-projects.info/",
+ "license": "LGPL-3",
"price": 50.00,
"currency": "EUR",
"depends": [
- "mail",
- "base",
- "mail_base"
+ "mail"
],
"external_dependencies": {"python": [], "bin": []},
"data": [
'template.xml',
'full_composer_wizard.xml',
],
+ "demo": [
+ ],
"qweb": [
'static/src/xml/mail_private.xml',
],
- "demo": [],
"post_load": None,
"pre_init_hook": None,
"post_init_hook": None,
+ "uninstall_hook": None,
"auto_install": False,
- "installable": False,
+ "installable": True,
+
+ # "demo_title": "{MODULE_NAME}",
+ # "demo_addons": [
+ # ],
+ # "demo_addons_hidden": [
+ # ],
+ # "demo_url": "DEMO-URL",
+ # "demo_summary": "{SHORT_DESCRIPTION_OF_THE_MODULE}",
+ # "demo_images": [
+ # "images/MAIN_IMAGE",
+ # ]
}
diff --git a/mail_private/full_composer_wizard.xml b/mail_private/full_composer_wizard.xml
index 9f57a20..1410548 100644
--- a/mail_private/full_composer_wizard.xml
+++ b/mail_private/full_composer_wizard.xml
@@ -1,4 +1,7 @@
+
diff --git a/mail_private/models.py b/mail_private/models.py
index dd6b60d..4ae1b91 100644
--- a/mail_private/models.py
+++ b/mail_private/models.py
@@ -1,3 +1,8 @@
+# Copyright 2016 x620
+# Copyright 2017 Artyom Losev
+# Copyright 2018 Ivan Yelizariev
+# Copyright 2019 Artem Rafailov
+# License LGPL-3.0 (https://www.gnu.org/licenses/lgpl.html).
from odoo import models, fields, api
@@ -41,68 +46,18 @@ class MailMessage(models.Model):
return result
@api.multi
- def _notify(self, force_send=False, send_after_commit=True, user_signature=True):
+ def _notify(self, record, msg_vals, force_send=False, send_after_commit=True, model_description=False, mail_auto_delete=True):
self_sudo = self.sudo()
- if not self_sudo.is_private:
- super(MailMessage, self)._notify(force_send, send_after_commit, user_signature)
+ msg_vals = msg_vals if msg_vals else {}
+ if 'is_private' not in self_sudo._context or not self_sudo._context['is_private']:
+ return super(MailMessage, self)._notify(record, msg_vals, force_send, send_after_commit, model_description, mail_auto_delete)
else:
- self._notify_mail_private(force_send, send_after_commit, user_signature)
+ rdata = self._notify_compute_internal_recipients(record, msg_vals)
+ return self._notify_recipients(rdata, record, msg_vals, force_send, send_after_commit, model_description, mail_auto_delete)
@api.multi
- def _notify_mail_private(self, force_send=False, send_after_commit=True, user_signature=True):
- """ Compute recipients to notify based on specified recipients and document
- followers. Delegate notification to partners to send emails and bus notifications
- 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 / ... )
- self_sudo = self.sudo()
-
- self.ensure_one()
- partners_sudo = self_sudo.partner_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
- if not self._context.get('mail_notify_author', False) and self_sudo.author_id:
- partners_sudo = partners_sudo - self_sudo.author_id
-
- # update message, with maybe custom valuesz
- message_values = {}
- if channels_sudo:
- message_values['channel_ids'] = [(6, 0, channels_sudo.ids)]
- if partners_sudo:
- message_values['needaction_partner_ids'] = [(6, 0, partners_sudo.ids)]
- if self.model and self.res_id and hasattr(self.env[self.model], 'message_get_message_notify_values'):
- message_values.update(self.env[self.model].browse(self.res_id).message_get_message_notify_values(self, message_values))
- if message_values:
- self.write(message_values)
-
- # notify partners and channels
- # those methods are called as SUPERUSER because portal users posting messages
- # have no access to partner model. Maybe propagating a real uid could be necessary.
- email_channels = channels_sudo.filtered(lambda channel: channel.email_send)
- notif_partners = partners_sudo.filtered(lambda partner: 'inbox' in partner.mapped('user_ids.notification_type'))
- if email_channels or partners_sudo - notif_partners:
- partners_sudo.search([
- '|',
- ('id', 'in', (partners_sudo - notif_partners).ids),
- ('channel_ids', 'in', email_channels.ids),
- ('email', '!=', self_sudo.author_id.email or self_sudo.email_from),
- ])._notify(self, force_send=force_send, send_after_commit=send_after_commit, user_signature=user_signature)
- channels_sudo._notify(self)
-
- # Discard cache, because child / parent allow reading and therefore
- # change access rights.
- if self.parent_id:
- self.parent_id.invalidate_cache()
-
- return True
+ def _notify_compute_internal_recipients(self, record, msg_vals):
+ recipient_data = super(MailMessage, self)._notify_compute_recipients(record, msg_vals)
+ pids = [x[1] for x in msg_vals.get('partner_ids')] if 'partner_ids' in msg_vals else self.sudo().partner_ids.ids
+ recipient_data['partners'] = [i for i in recipient_data['partners'] if i['id'] in pids]
+ return recipient_data
diff --git a/mail_private/static/src/js/mail_private.js b/mail_private/static/src/js/mail_private.js
index 4b3a7d0..8432807 100644
--- a/mail_private/static/src/js/mail_private.js
+++ b/mail_private/static/src/js/mail_private.js
@@ -2,19 +2,19 @@
Copyright 2016 manavi
Copyright 2017-2018 Artyom Losev
Copyright 2018 Kolushov Alexandr
+ Copyright 2019 Artem Rafailov
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). */
odoo.define('mail_private', function (require) {
'use strict';
var core = require('web.core');
var Chatter = require('mail.Chatter');
-var ChatterComposer = require('mail.ChatterComposer');
-var chat_manager = require('mail_base.base').chat_manager;
+var ChatterComposer = require('mail.composer.Chatter');
var session = require('web.session');
var rpc = require('web.rpc');
var config = require('web.config');
-var utils = require('mail.utils');
+var mailUtils = require('mail.utils');
Chatter.include({
@@ -36,51 +36,55 @@ Chatter.include({
_openComposer: function (options) {
var self = this;
- var old_composer = this.composer;
+ var old_composer = this._composer;
// create the new composer
- this.composer = new ChatterComposer(this, this.record.model, options.suggested_partners || [], {
- commands_enabled: false,
+ this._composer = new ChatterComposer(this, this.record.model, options.suggested_partners || [], {
+ commandsEnabled: false,
context: this.context,
- input_min_height: 50,
- input_max_height: Number.MAX_VALUE,
- input_baseline: 14,
- is_log: options && options.is_log,
- record_name: this.record_name,
- default_body: old_composer && old_composer.$input && old_composer.$input.val(),
- default_mention_selections: old_composer && old_composer.mention_get_listener_selections(),
+ inputMinHeight: 50,
+ isLog: options && options.isLog,
+ recordName: this.recordName,
+ defaultBody: old_composer && old_composer.$input && old_composer.$input.val(),
+ defaultMentionSelections: old_composer && old_composer.getMentionListenerSelections(),
+ attachmentIds: (old_composer && old_composer.get('attachment_ids')) || [],
is_private: options.is_private
});
- this.composer.on('input_focused', this, function () {
- this.composer.mention_set_prefetched_partners(this.mentionSuggestions || []);
+ this._composer.on('input_focused', this, function () {
+ this._composer.mentionSetPrefetchedPartners(this._mentionSuggestions || []);
});
- this.composer.insertAfter(this.$('.o_chatter_topbar')).then(function () {
+ this._composer.insertAfter(this.$('.o_chatter_topbar')).then(function () {
// destroy existing composer
if (old_composer) {
old_composer.destroy();
}
- if (!config.device.touch) {
- self.composer.focus();
- }
- self.composer.on('post_message', self, function (message) {
+ self._composer.focus();
+ self._composer.on('post_message', self, function (messageData) {
if (options.is_private) {
- self.composer.options.is_log = true;
+ self._composer.options.isLog = true;
}
- self.fields.thread.postMessage(message).then(function () {
-
- self._closeComposer(true);
- if (self.postRefresh === 'always' || (self.postRefresh === 'recipients' && message.partner_ids.length)) {
- self.trigger_up('reload');
- }
+ self._discardOnReload(messageData).then(function () {
+ self._disableComposer();
+ self.fields.thread.postMessage(messageData).then(function () {
+ self._closeComposer(true);
+ if (self._reloadAfterPost(messageData)) {
+ self.trigger_up('reload');
+ } else if (messageData.attachment_ids.length) {
+ self._reloadAttachmentBox();
+ self.trigger_up('reload', {fieldNames: ['message_attachment_count'], keepChanges: true});
+ }
+ }).fail(function () {
+ self._enableComposer();
+ });
});
});
- var toggle_post_private = self.composer.options.is_private || false;
- self.composer.on('need_refresh', self, self.trigger_up.bind(self, 'reload'));
- self.composer.on('close_composer', null, self._closeComposer.bind(self, true));
+ var toggle_post_private = self._composer.options.is_private || false;
+ self._composer.on('need_refresh', self, self.trigger_up.bind(self, 'reload'));
+ self._composer.on('close_composer', null, self._closeComposer.bind(self, true));
self.$el.addClass('o_chatter_composer_active');
self.$('.o_chatter_button_new_message, .o_chatter_button_log_note, .oe_compose_post_private').removeClass('o_active');
- self.$('.o_chatter_button_new_message').toggleClass('o_active', !self.composer.options.is_log && !self.composer.options.is_private);
- self.$('.o_chatter_button_log_note').toggleClass('o_active', (self.composer.options.is_log && !options.is_private));
+ self.$('.o_chatter_button_new_message').toggleClass('o_active', !self._composer.options.isLog && !self._composer.options.is_private);
+ self.$('.o_chatter_button_log_note').toggleClass('o_active', self._composer.options.isLog && !options.is_private);
self.$('.oe_compose_post_private').toggleClass('o_active', toggle_post_private);
});
},
@@ -102,8 +106,8 @@ Chatter.include({
});
ChatterComposer.include({
- init: function (parent, model, suggested_partners, options) {
- this._super(parent, model, suggested_partners, options);
+ init: function (parent, model, suggestedPartners, options) {
+ this._super(parent, model, suggestedPartners, options);
this.events['click .oe_composer_uncheck'] = 'on_uncheck_recipients';
if (typeof options.is_private === 'undefined') {
// otherwise it causes an error in context creating function
@@ -111,40 +115,39 @@ ChatterComposer.include({
}
},
- preprocess_message: function () {
+ _preprocessMessage: function () {
var self = this;
var def = $.Deferred();
this._super().then(function (message) {
message = _.extend(message, {
subtype: 'mail.mt_comment',
message_type: 'comment',
- content_subtype: 'html',
- context: self.context,
+ context: _.defaults({}, self.context, session.user_context),
});
// Subtype
- if (self.options.is_log) {
+ if (self.options.isLog) {
message.subtype = 'mail.mt_note';
}
if (self.options.is_private) {
- message.is_private = true;
+ message.context.is_private = true;
message.channel_ids = self.get_checked_channel_ids();
}
// Partner_ids
- if (!self.options.is_log) {
- var checked_suggested_partners = self.get_checked_suggested_partners();
- self.check_suggested_partners(checked_suggested_partners).done(function (partner_ids) {
- message.partner_ids = (message.partner_ids || []).concat(partner_ids);
+ if (self.options.isLog) {
+ def.resolve(message);
+ } else {
+ var check_suggested_partners = self._getCheckedSuggestedPartners();
+ self._checkSuggestedPartners(check_suggested_partners).done(function (partnerIDs) {
+ message.partner_ids = (message.partner_ids || []).concat(partnerIDs);
// update context
message.context = _.defaults({}, message.context, {
mail_post_autofollow: true,
});
def.resolve(message);
});
- } else {
- def.resolve(message);
}
});
return def;
@@ -156,25 +159,30 @@ ChatterComposer.include({
});
},
- on_open_full_composer: function() {
- if (!this.do_check_attachment_upload()){
+ _onOpenFullComposer: function () {
+ if (!this._doCheckAttachmentUpload()){
return false;
}
var self = this;
- var recipient_done = $.Deferred();
- if (this.options.is_log) {
- recipient_done.resolve([]);
- } else {
- var checked_suggested_partners = this.get_checked_suggested_partners();
- recipient_done = this.check_suggested_partners(checked_suggested_partners);
- }
- recipient_done.then(function (partner_ids) {
+ var recipientDoneDef = $.Deferred();
+ this.trigger_up('discard_record_changes', {
+ proceed: function () {
+ if (self.options.isLog) {
+ recipientDoneDef.resolve([]);
+ } else {
+ var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
+ self._checkSuggestedPartners(checkedSuggestedPartners)
+ .then(recipientDoneDef.resolve.bind(recipientDoneDef));
+ }
+ },
+ });
+ recipientDoneDef.then(function (partnerIDs) {
var context = {
default_parent_id: self.id,
- default_body: utils.get_text2html(self.$input.val()),
+ default_body: mailUtils.getTextToHTML(self.$input.val()),
default_attachment_ids: _.pluck(self.get('attachment_ids'), 'id'),
- default_partner_ids: partner_ids,
- default_is_log: self.options.is_log,
+ default_partner_ids: partnerIDs,
+ default_is_log: self.options.isLog,
mail_post_autofollow: true,
is_private: self.options.is_private,
};
@@ -187,7 +195,7 @@ ChatterComposer.include({
context.default_model = self.context.default_model;
context.default_res_id = self.context.default_res_id;
}
- self.do_action({
+ var action = {
type: 'ir.actions.act_window',
res_model: 'mail.compose.message',
view_mode: 'form',
@@ -195,17 +203,14 @@ ChatterComposer.include({
views: [[false, 'form']],
target: 'new',
context: context,
- }, {
- on_close: function() {
- self.trigger('need_refresh');
- var parent = self.getParent();
- chat_manager.get_messages({model: parent.model, res_id: parent.res_id});
- },
+ };
+ self.do_action(action, {
+ on_close: self.trigger.bind(self, 'need_refresh'),
}).then(self.trigger.bind(self, 'close_composer'));
});
},
- get_checked_suggested_partners: function () {
+ _getCheckedSuggestedPartners: function () {
var checked_partners = this._super(this, arguments);
// workaround: odoo code works only when all partners are checked intially,
// while may select only some of them (internal recepients)
diff --git a/mail_private/static/src/js/test_private.js b/mail_private/static/src/js/test_private.js
index 4b6efda..2b30b4d 100644
--- a/mail_private/static/src/js/test_private.js
+++ b/mail_private/static/src/js/test_private.js
@@ -1,17 +1,30 @@
-/* Copyright 2018 Kolushov Alexandr
+/* Copyright 2018-2019 Kolushov Alexandr
+ Copyright 2019 Artem Rafailov
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).*/
-odoo.define('mail_private.tour', function (require) {
- "use strict";
+odoo.define('mail_private.tour', function(require) {
+"use strict";
- var tour = require("web_tour.tour");
var core = require('web.core');
+ var tour = require('web_tour.tour');
var _t = core._t;
var email = 'mail_private test email';
- var steps = [{
- trigger: '.o_thread_message strong.o_mail_redirect:contains("Agrolait")',
- content: _t("Open Partners Form"),
+ var steps = [tour.STEPS.SHOW_APPS_MENU_ITEM, {
+ trigger: '.fa.fa-cog.o_mail_channel_settings',
+ content: _t('Select channel settings'),
position: 'bottom',
+ }, {
+ trigger: '.nav-link:contains("Members")',
+ content: _t('Go to the list of subscribers'),
+ position: 'bottom',
+ }, {
+ trigger: '.o_data_cell:contains("YourCompany, Marc Demo")',
+ content: _t("Select a user"),
+ position: "bottom",
+ }, {
+ trigger: '.o_form_uri.o_field_widget:contains("YourCompany, Marc Demo")',
+ content: _t("Go to user page"),
+ position: "bottom"
}, {
trigger: "button.oe_compose_post_private",
content: _t("Click on Private mail creating button"),
@@ -26,7 +39,7 @@ odoo.define('mail_private.tour', function (require) {
content: _t("Uncheck all Followers"),
timeout: 10000,
}, {
- trigger: "div.o_composer_suggested_partners input:first",
+ trigger: "div.o_composer_suggested_partners",
content: _t("Check the first one"),
}, {
trigger: "textarea.o_composer_text_field:first",
diff --git a/mail_private/static/src/xml/mail_private.xml b/mail_private/static/src/xml/mail_private.xml
index baadbb5..f04b9db 100644
--- a/mail_private/static/src/xml/mail_private.xml
+++ b/mail_private/static/src/xml/mail_private.xml
@@ -1,13 +1,16 @@
+
-
+
-
+
-
+
To: Followers of
@@ -20,7 +23,7 @@
-
+
diff --git a/mail_private/template.xml b/mail_private/template.xml
index 842bdf0..09bc6ec 100644
--- a/mail_private/template.xml
+++ b/mail_private/template.xml
@@ -1,4 +1,7 @@
+
+# Copyright 2019 Artem Rafailov
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
import odoo.tests
-from odoo.api import Environment
@odoo.tests.common.at_install(True)
@@ -16,15 +15,8 @@ class TestUi(odoo.tests.HttpCase):
# that are returned by the backend in module_boot. Without
# this you end up with js, css but no qweb.
cr = self.registry.cursor()
- env = Environment(cr, self.uid, {})
- env['ir.module.module'].search([('name', '=', 'mail_private')], limit=1).state = 'installed'
- cr.release()
-
- env = Environment(self.registry.test_cr, self.uid, {})
- partners = env['res.partner'].search([])
- new_follower = env['res.partner'].search([('name', 'ilike', 'Ja')])
- for partner in partners:
- partner.message_subscribe(new_follower.ids, [])
+ self.env['ir.module.module'].search([('name', '=', 'mail_private')], limit=1).state = 'installed'
+ cr._lock.release()
self.phantom_js("/web",
"odoo.__DEBUG__.services['web_tour.tour'].run('mail_private_tour', 1000)",