[MERGE] mail: clearly separate email from inbox notification management

This merge changes the way odoo handles notifications. Previously
notifications were sent to the odoo inbox and forwarded by email
depending on a parameter on the partner. Now users choose whether to
use odoo inbox or email but not both. Customers only work using
emails from now on.

This merge also features side commits linked to notifications and mail
like making mail tests less dependent on channels, the removal of auto
read in channels, limitation of assigned emails and project subscription
improvements.
This commit is contained in:
Thibault Delavallée
2017-02-21 17:30:38 +01:00
38 changed files with 506 additions and 536 deletions
@@ -25,21 +25,17 @@ class TestFiscalPosition(common.TransactionCase):
self.jc = self.res_partner.create(dict(
name="JCVD",
vat="BE0477472701",
notify_email="none",
country_id=be.id))
self.ben = self.res_partner.create(dict(
name="BP",
notify_email="none",
country_id=be.id))
self.george = self.res_partner.create(dict(
name="George",
vat="BE0477472701",
notify_email="none",
country_id=fr.id))
self.alberto = self.res_partner.create(dict(
name="Alberto",
vat="BE0477472701",
notify_email="none",
country_id=mx.id))
self.be_nat = self.fp.create(dict(
name="BE-NAT",
+3 -2
View File
@@ -2,9 +2,9 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests.common import TransactionCase
from odoo.addons.mail.tests.common import TestMail
from odoo.addons.mail.tests.common import BaseFunctionalTest
class TestCrm(TestMail):
class TestCrm(BaseFunctionalTest):
@classmethod
def setUpClass(cls):
@@ -19,6 +19,7 @@ class TestCrm(TestMail):
'name': 'Riton La Chignole',
'login': 'riton',
'email': 'riton.salesman_all@example.com',
'notification_type': 'inbox',
'groups_id': [(6, 0, [user_group_employee.id, user_group_salesman_all.id])]
})
@@ -12,7 +12,7 @@ class NewLeadNotification(TestCrm):
# subscribe a partner and a channel to the sales channel with new lead subtype
subtype = self.env.ref("crm.mt_salesteam_lead")
self.sales_team_1.message_subscribe(partner_ids=[self.user_salesman_all.partner_id.id], subtype_ids=[subtype.id])
self.sales_team_1.message_subscribe(channel_ids=[self.group_pigs.id], subtype_ids=[subtype.id])
self.sales_team_1.message_subscribe(channel_ids=[self.channel_listen.id], subtype_ids=[subtype.id])
# Imitate what happens in the controller when somebody creates a new
# lead from the website form
@@ -27,11 +27,11 @@ class NewLeadNotification(TestCrm):
})
# partner and channel should be auto subscribed
self.assertIn(self.user_salesman_all.partner_id, lead.message_partner_ids)
self.assertIn(self.group_pigs, lead.message_channel_ids)
self.assertIn(self.channel_listen, lead.message_channel_ids)
msg = lead.message_ids[0]
self.assertIn(self.user_salesman_all.partner_id, msg.needaction_partner_ids)
self.assertIn(self.group_pigs, msg.channel_ids)
self.assertIn(self.channel_listen, msg.channel_ids)
# The user should have a new unread message
lead_user = lead.sudo(self.user_salesman_all)
+3 -3
View File
@@ -27,9 +27,9 @@
<field name="priority">1000</field>
</record>
<!-- Admin should not receivve emails at creation -->
<record id="base.partner_root" model="res.partner">
<field name="notify_email">none</field>
<!-- Admin should not receive emails at creation -->
<record id="base.user_root" model="res.users">
<field name="notification_type">inbox</field>
</record>
<!-- Catchall Email Alias -->
+2 -68
View File
@@ -3,75 +3,9 @@
<data noupdate="1">
<!-- Update 'Demo user' and partners email preferences to avoid mail bombing -->
<record id="base.partner_demo" model="res.partner">
<!-- <record id="base.partner_demo" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_1" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_2" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_3" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_4" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_3" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_1" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_4" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_12" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_12" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_10" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_3" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_12" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_2" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_4" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_3" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_1" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_12" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_18" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_2" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_4" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_1" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_12" model="res.partner">
<field name="notify_email">none</field>
</record>
</record> -->
<!-- Thread: 1 incoming email -->
<record id="msg_discus5" model="mail.message">
+27 -19
View File
@@ -761,18 +761,16 @@ class Message(models.Model):
@api.multi
def _notify(self, force_send=False, send_after_commit=True, user_signature=True):
""" Add the related record followers to the destination partner_ids if is not a private message.
Call mail_notification.notify to manage the email sending
"""
""" 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 / ...
# have a sudoed copy to manipulate partners (public can go here with website modules like forum / blog / ... )
self_sudo = self.sudo()
# TDE CHECK: add partners / channels as arguments to be able to notify a message with / without computation ??
self.ensure_one() # tde: not sure, just for testinh, will see
partners = self.env['res.partner'] | self.partner_ids
channels = self.env['mail.channel'] | self.channel_ids
self.ensure_one()
partners_sudo = self.env['res.partner'].sudo() | self_sudo.partner_ids
channels_sudo = self.env['mail.channel'].sudo() | self_sudo.channel_ids
# all followers of the mail.message document have to be added as partners and notified
# and filter to employees only if the subtype is internal
@@ -783,28 +781,38 @@ class Message(models.Model):
]).filtered(lambda fol: self.subtype_id in fol.subtype_ids)
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 = self_sudo.channel_ids | followers.mapped('channel_id')
partners = self_sudo.partner_ids | followers.mapped('partner_id')
else:
channels = self_sudo.channel_ids
partners = self_sudo.partner_ids
channels_sudo |= followers.mapped('channel_id')
partners_sudo |= followers.mapped('partner_id')
# remove author from notified partners
if not self._context.get('mail_notify_author', False) and self_sudo.author_id:
partners = partners - self_sudo.author_id
partners_sudo = partners_sudo - self_sudo.author_id
# update message, with maybe custom values
message_values = {
'channel_ids': [(6, 0, channels.ids)],
'needaction_partner_ids': [(6, 0, partners.ids)]
'channel_ids': [(6, 0, channels_sudo.ids)],
'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))
self.write(message_values)
# notify partners and channels
partners._notify(self, force_send=force_send, send_after_commit=send_after_commit, user_signature=user_signature)
channels._notify(self)
# 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)
# make a dedicated search on res.users to avoid user_ids.notification_type that will be user_ids.id in [ARRAY]
notif_users = self.env['res.users'].sudo().search([
('partner_id', 'in', partners_sudo.ids),
('notification_type', '=', 'inbox')
])
partners_sudo.search([
'|',
('id', 'in', (partners_sudo - notif_users.mapped('partner_id')).ids),
('channel_ids', 'in', email_channels.ids),
('email', '!=', self_sudo.author_id and 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.
+4 -5
View File
@@ -2134,10 +2134,9 @@ class MailThread(models.AbstractModel):
new_channels.setdefault(header_follower.channel_id.id, set()).add(new_subtype.id)
# add followers coming from res.users relational fields that are tracked
user_ids = [values[name] for name in user_field_lst if values.get(name)]
user_pids = [user.partner_id.id for user in self.env['res.users'].sudo().browse(user_ids)]
for partner_id in user_pids:
new_partners.setdefault(partner_id, None)
to_add_users = self.env['res.users'].sudo().browse([values[name] for name in user_field_lst if values.get(name)])
for partner in to_add_users.mapped('partner_id'):
new_partners.setdefault(partner.id, None)
for pid, subtypes in new_partners.items():
subtypes = list(subtypes) if subtypes is not None else None
@@ -2147,7 +2146,7 @@ class MailThread(models.AbstractModel):
self.message_subscribe(channel_ids=[cid], subtype_ids=subtypes, force=(subtypes != None))
# remove the current user from the needaction partner to avoid to notify the author of the message
user_pids = [user_pid for user_pid in user_pids if user_pid != self.env.user.partner_id.id]
user_pids = [user.partner_id.id for user in to_add_users if user != self.env.user and user.notification_type == 'email']
self._message_auto_subscribe_notify(user_pids)
return True
+1 -22
View File
@@ -19,14 +19,6 @@ class Partner(models.Model):
_mail_mass_mailing = _('Customers')
message_bounce = fields.Integer('Bounce', help="Counter of the number of bounced emails for this contact")
notify_email = fields.Selection([
('none', 'Never'),
('always', 'All Messages')],
'Email Messages and Notifications', required=True,
oldname='notification_email_send', default='always',
help="Policy to receive emails for new messages pushed to your personal Inbox:\n"
"- Never: no emails are sent\n"
"- All Messages: for every notification you receive in your Inbox")
opt_out = fields.Boolean(
'Opt-Out', help="If opt-out is checked, this contact has refused to receive emails for mass mailing and marketing campaign. "
"Filter 'Available for Mass Mailing' allows users to filter the partners when performing mass mailing.")
@@ -140,25 +132,12 @@ class Partner(models.Model):
('res_partner_id', 'in', email.recipient_ids.ids)])
notifications.write({
'is_email': True,
'is_read': True, # handle by email discards Inbox notification
'email_status': 'ready',
})
@api.multi
def _notify(self, message, force_send=False, send_after_commit=True, user_signature=True):
# TDE TODO: model-dependant ? (like customer -> always email ?)
message_sudo = message.sudo()
email_channels = message.channel_ids.filtered(lambda channel: channel.email_send)
self.sudo().search([
'|',
('id', 'in', self.ids),
('channel_ids', 'in', email_channels.ids),
('email', '!=', message_sudo.author_id and message_sudo.author_id.email or message.email_from),
('notify_email', '!=', 'none')])._notify_by_email(message, force_send=force_send, send_after_commit=send_after_commit, user_signature=user_signature)
self._notify_by_chat(message)
return True
@api.multi
def _notify_by_email(self, message, force_send=False, send_after_commit=True, user_signature=True):
""" Method to send email linked to notified messages. The recipients are
the recordset on which this method is called.
+9 -2
View File
@@ -23,6 +23,13 @@ class Users(models.Model):
('everyone', 'Everyone'),
('partners', 'Authenticated Partners'),
('followers', 'Followers only')], string='Alias Contact Security', related='alias_id.alias_contact')
notification_type = fields.Selection([
('email', 'Handle by Emails'),
('inbox', 'Handle in Odoo')],
'Notification Management', required=True, default='email',
help="Policy on how to handle Chatter notifications:\n"
"- Emails: notifications are sent to your email\n"
"- Odoo: notifications appear in your Odoo Inbox")
def __init__(self, pool, cr):
""" Override of __init__ to add access rights on notification_email_send
@@ -32,10 +39,10 @@ class Users(models.Model):
init_res = super(Users, self).__init__(pool, cr)
# duplicate list to avoid modifying the original reference
type(self).SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS)
type(self).SELF_WRITEABLE_FIELDS.extend(['notify_email'])
type(self).SELF_WRITEABLE_FIELDS.extend(['notification_type'])
# duplicate list to avoid modifying the original reference
type(self).SELF_READABLE_FIELDS = list(self.SELF_READABLE_FIELDS)
type(self).SELF_READABLE_FIELDS.extend(['notify_email'])
type(self).SELF_READABLE_FIELDS.extend(['notification_type'])
return init_res
@api.model
+2 -1
View File
@@ -33,7 +33,8 @@ access_mail_template,mail.template,model_mail_template,base.group_user,1,1,1,0
access_mail_template_system,mail.template_system,model_mail_template,base.group_system,1,1,1,1
access_mail_shortcode,mail.shortcode,model_mail_shortcode,base.group_user,1,1,1,1
access_mail_shortcode_portal,mail.shortcode.portal,model_mail_shortcode,base.group_portal,1,0,0,0
access_mail_test_all,mail.test.all,model_mail_test,base.group_user,1,1,1,1
access_mail_test_user,mail.test.all,model_mail_test,base.group_user,1,1,1,1
access_mail_test_portal,mail.test.all,model_mail_test,base.group_portal,1,1,0,0
access_mail_activity_all,mail.activity.all,model_mail_activity,,1,0,0,0
access_mail_activity_user,mail.activity.user,model_mail_activity,base.group_user,1,1,1,1
access_mail_activity_type_all,mail.activity.type.all,model_mail_activity_type,,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
33 access_mail_template_system mail.template_system model_mail_template base.group_system 1 1 1 1
34 access_mail_shortcode mail.shortcode model_mail_shortcode base.group_user 1 1 1 1
35 access_mail_shortcode_portal mail.shortcode.portal model_mail_shortcode base.group_portal 1 0 0 0
36 access_mail_test_all access_mail_test_user mail.test.all model_mail_test base.group_user 1 1 1 1
37 access_mail_test_portal mail.test.all model_mail_test base.group_portal 1 1 0 0
38 access_mail_activity_all mail.activity.all model_mail_activity 1 0 0 0
39 access_mail_activity_user mail.activity.user model_mail_activity base.group_user 1 1 1 1
40 access_mail_activity_type_all mail.activity.type.all model_mail_activity_type 1 0 0 0
@@ -111,14 +111,6 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
var channel_id = $(event.target).data("channel-id");
chat_manager.unsubscribe(chat_manager.get_channel(channel_id));
},
"click .o_snackbar_undo": function (event) {
event.preventDefault();
var channel = this.channel;
this.$snackbar.remove();
this.clear_needactions_def.then(function (msgs_ids) {
chat_manager.undo_mark_as_read(msgs_ids, channel);
});
},
"click .o_mail_annoying_notification_bar .fa-close": function () {
this.$(".o_mail_annoying_notification_bar").slideUp();
},
@@ -425,7 +417,6 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
this.messages_separator_position = undefined; // reset value on channel change
this.unread_counter = this.channel.unread_counter;
this.last_seen_message_id = this.channel.last_seen_message_id;
this.clear_needactions_def = $.Deferred();
if (this.$snackbar) {
this.$snackbar.remove();
}
@@ -436,14 +427,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
return this.fetch_and_render_thread().then(function () {
// Mark channel's messages as read and clear needactions
if (channel.type !== 'static') {
// Display snackbar if needactions have been cleared
if (channel.needaction_counter > 0) {
self.render_snackbar('mail.chat.UndoSnackbar', {
nb_needactions: channel.needaction_counter,
});
}
chat_manager.mark_channel_as_seen(channel);
self.clear_needactions_def = chat_manager.mark_all_as_read(channel);
}
// Update control panel
@@ -50,8 +50,7 @@ var FieldMany2ManyTagsEmail = form_relational.FieldMany2ManyTags.extend({
var self = this;
new Model('res.partner').call("search", [[
["id", "in", ids],
["email", "=", false],
["notify_email", "=", 'always'] ]],
["email", "=", false] ]],
{context: this.build_context()})
.then(function (record_ids) {
// valid partner
@@ -167,10 +167,6 @@
cursor: pointer;
background-color: darken(@gray, 8%);
color: white;
.o_snackbar_undo {
margin-left: 8px;
padding: 8px;
}
}
}
}
@@ -113,13 +113,6 @@
<i t-if="status == 'offline'" class="o_mail_user_status fa fa-circle-o" title="Offline"/>
</t>
<t t-name="mail.chat.UndoSnackbar">
<div class="alert o_mail_snackbar" data-dismiss="alert" role="alert">
<t t-esc="nb_needactions"/> mention(s) marked as read.
<a href="#" class="alert-link o_snackbar_undo">Undo</a>
</div>
</t>
<t t-name="mail.chat.MessageSentSnackbar">
<div class="alert o_mail_snackbar" data-dismiss="alert" role="alert">
Message sent in "<t t-esc="record_name"/>".
+56 -60
View File
@@ -4,7 +4,49 @@ from odoo import api
from odoo.tests import common
class TestMail(common.SavepointCase):
class BaseFunctionalTest(common.SavepointCase):
@classmethod
def setUpClass(cls):
super(BaseFunctionalTest, cls).setUpClass()
# User groups
user_group_employee = cls.env.ref('base.group_user')
user_group_portal = cls.env.ref('base.group_portal')
user_group_public = cls.env.ref('base.group_public')
# User Data: employee, noone
Users = cls.env['res.users'].with_context({'no_reset_password': True, 'mail_create_nosubscribe': True})
cls.user_employee = Users.create({
'name': 'Ernest Employee',
'login': 'ernest',
'email': 'e.e@example.com',
'signature': '--\nErnest',
'notification_type': 'email',
'groups_id': [(6, 0, [user_group_employee.id])]})
cls.user_public = Users.create({
'name': 'Bert Tartignole',
'login': 'bert',
'email': 'b.t@example.com',
'signature': 'SignBert',
'notification_type': 'email',
'groups_id': [(6, 0, [user_group_public.id])]})
cls.user_portal = Users.create({
'name': 'Chell Gladys',
'login': 'chell',
'email': 'chell@gladys.portal',
'signature': 'SignChell',
'notification_type': 'email',
'groups_id': [(6, 0, [user_group_portal.id])]})
cls.user_admin = cls.env.user
# Listener channel
cls.channel_listen = cls.env['mail.channel'].with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True
}).create({'name': 'Listener'})
class TestMail(BaseFunctionalTest):
@classmethod
def _init_mock_build_email(cls):
@@ -14,7 +56,7 @@ class TestMail(common.SavepointCase):
def format_and_process(self, template, to='groups@example.com, other@gmail.com', subject='Frogs',
extra='', email_from='Sylvie Lelitre <test.sylvie.lelitre@agrolait.com>',
cc='', msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>',
model=None, target_model='mail.channel', target_field='name'):
model=None, target_model='mail.test', target_field='name'):
self.assertFalse(self.env[target_model].search([(target_field, '=', subject)]))
mail = template.format(to=to, subject=subject, cc=cc, extra=extra, email_from=email_from, msg_id=msg_id)
self.env['mail.thread'].with_context(mail_channel_noautofollow=True).message_process(model, mail)
@@ -38,82 +80,37 @@ class TestMail(common.SavepointCase):
def send_email(self, message, *args, **kwargs):
return message['Message-Id']
@api.multi
def mail_group_message_get_recipient_values(self, notif_message=None, recipient_ids=None):
return self.env['mail.thread'].message_get_recipient_values(notif_message=notif_message, recipient_ids=recipient_ids)
cls.env['ir.mail_server']._patch_method('build_email', build_email)
cls.env['ir.mail_server']._patch_method('send_email', send_email)
cls.env['mail.channel']._patch_method('message_get_recipient_values', mail_group_message_get_recipient_values)
# User groups
user_group_employee = cls.env.ref('base.group_user')
user_group_portal = cls.env.ref('base.group_portal')
user_group_public = cls.env.ref('base.group_public')
# User Data: employee, noone
Users = cls.env['res.users'].with_context({'no_reset_password': True, 'mail_create_nosubscribe': True})
cls.user_employee = Users.create({
'name': 'Ernest Employee',
'login': 'ernest',
'email': 'e.e@example.com',
'signature': '--\nErnest',
'notify_email': 'always',
'groups_id': [(6, 0, [user_group_employee.id])]})
cls.user_public = Users.create({
'name': 'Bert Tartignole',
'login': 'bert',
'email': 'b.t@example.com',
'signature': 'SignBert',
'notify_email': 'always',
'groups_id': [(6, 0, [user_group_public.id])]})
cls.user_portal = Users.create({
'name': 'Chell Gladys',
'login': 'chell',
'email': 'chell@gladys.portal',
'signature': 'SignChell',
'notify_email': 'always',
'groups_id': [(6, 0, [user_group_portal.id])]})
cls.user_admin = cls.env.user
# Test Data for Partners
cls.partner_1 = cls.env['res.partner'].create({
'name': 'Valid Lelitre',
'email': 'valid.lelitre@agrolait.com',
'notify_email': 'always'})
'email': 'valid.lelitre@agrolait.com'})
cls.partner_2 = cls.env['res.partner'].create({
'name': 'Valid Poilvache',
'email': 'valid.other@gmail.com',
'notify_email': 'always'})
'email': 'valid.other@gmail.com'})
# Create test groups without followers and messages by default
TestMailGroup = cls.env['mail.channel'].with_context({
TestModel = cls.env['mail.test'].with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True,
'mail_channel_noautofollow': True,
})
# Pigs: base group for tests
cls.group_pigs = TestMailGroup.create({
cls.test_pigs = TestModel.create({
'name': 'Pigs',
'description': 'Fans of Pigs, unite !',
'public': 'groups',
'group_public_id': user_group_employee.id,
'alias_name': 'pigs',
'alias_contact': 'followers'}
).with_context({'mail_create_nosubscribe': False})
# Jobs: public group
cls.group_public = TestMailGroup.create({
'name': 'Jobs',
'alias_contact': 'followers',
})
cls.test_public = TestModel.create({
'name': 'Public',
'description': 'NotFalse',
'public': 'public',
'alias_name': 'public',
'alias_contact': 'everyone'}
).with_context({'mail_create_nosubscribe': False})
'alias_contact': 'everyone'
})
# remove default followers
cls.env['mail.followers'].search([
('res_model', '=', 'mail.channel'),
('res_id', 'in', (cls.group_pigs | cls.group_public).ids)]).unlink()
('res_model', '=', 'mail.test'),
('res_id', 'in', (cls.test_public | cls.test_pigs).ids)]).unlink()
cls._init_mock_build_email()
@@ -122,5 +119,4 @@ class TestMail(common.SavepointCase):
# Remove mocks
cls.env['ir.mail_server']._revert_method('build_email')
cls.env['ir.mail_server']._revert_method('send_email')
cls.env['mail.channel']._revert_method('message_get_recipient_values')
super(TestMail, cls).tearDownClass()
+8 -8
View File
@@ -10,30 +10,30 @@ class TestInvite(TestMail):
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_invite_email(self):
mail_invite = self.env['mail.wizard.invite'].with_context({
'default_res_model': 'mail.channel',
'default_res_id': self.group_pigs.id
'default_res_model': 'mail.test',
'default_res_id': self.test_pigs.id
}).sudo(self.user_employee.id).create({
'partner_ids': [(4, self.user_portal.partner_id.id), (4, self.partner_1.id)],
'send_mail': True})
mail_invite.add_followers()
# Test: Pigs followers should contain Admin, Bert
self.assertEqual(self.group_pigs.message_partner_ids,
self.assertEqual(self.test_pigs.message_partner_ids,
self.user_portal.partner_id | self.partner_1,
'invite wizard: Pigs followers after invite is incorrect, should be Admin + added follower')
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'),
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'),
self.env['mail.channel'],
'invite wizard: Pigs followers after invite is incorrect, should not have channels')
# Test: (pretend to) send email and check subject, body
self.assertEqual(len(self._mails), 2, 'invite wizard: sent email number incorrect, should be only for Bert')
self.assertEqual(self._mails[0].get('subject'), 'Invitation to follow Discussion channel: Pigs',
self.assertEqual(self._mails[0].get('subject'), 'Invitation to follow %s: Pigs' % self.env['mail.test']._description,
'invite wizard: subject of invitation email is incorrect')
self.assertEqual(self._mails[1].get('subject'), 'Invitation to follow Discussion channel: Pigs',
self.assertEqual(self._mails[1].get('subject'), 'Invitation to follow %s: Pigs' % self.env['mail.test']._description,
'invite wizard: subject of invitation email is incorrect')
self.assertIn('%s invited you to follow Discussion channel document: Pigs' % self.user_employee.name,
self.assertIn('%s invited you to follow %s document: Pigs' % (self.user_employee.name, self.env['mail.test']._description),
self._mails[0].get('body'),
'invite wizard: body of invitation email is incorrect')
self.assertIn('%s invited you to follow Discussion channel document: Pigs' % self.user_employee.name,
self.assertIn('%s invited you to follow %s document: Pigs' % (self.user_employee.name, self.env['mail.test']._description),
self._mails[1].get('body'),
'invite wizard: body of invitation email is incorrect')
+17 -7
View File
@@ -14,16 +14,26 @@ class TestMailGroup(TestMail):
def setUpClass(cls):
super(TestMailGroup, cls).setUpClass()
# for specific tests of mail channel, get back to its expected behavior
cls.registry('mail.channel')._revert_method('message_get_recipient_values')
# Private: private group
cls.group_private = cls.env['mail.channel'].with_context({
# cls.registry('mail.channel')._revert_method('message_get_recipient_values')
Channel = cls.env['mail.channel'].with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True
}).create({
})
# Pigs: base group for tests
cls.group_pigs = Channel.create({
'name': 'Pigs',
'public': 'groups',
'group_public_id': cls.env.ref('base.group_user').id})
# Jobs: public group
cls.group_public = Channel.create({
'name': 'Jobs',
'description': 'NotFalse',
'public': 'public'})
# Private: private group
cls.group_private = Channel.create({
'name': 'Private',
'public': 'private'}
).with_context({'mail_create_nosubscribe': False})
'public': 'private'})
@classmethod
def tearDownClass(cls):
+95 -79
View File
@@ -10,7 +10,7 @@ class TestMailFeatures(TestMail):
# TDE TODO: tests on the redirection controller
def test_alias_setup(self):
alias = self.env['mail.alias'].with_context(alias_model_name='mail.channel').create({'alias_name': 'b4r+_#_R3wl$$'})
alias = self.env['mail.alias'].with_context(alias_model_name='mail.test').create({'alias_name': 'b4r+_#_R3wl$$'})
self.assertEqual(alias.alias_name, 'b4r+_-_r3wl-', 'Disallowed chars should be replaced by hyphens')
def test_10_cache_invalidation(self):
@@ -26,13 +26,16 @@ class TestMailFeatures(TestMail):
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_needaction(self):
na_emp1_base = self.group_pigs.sudo(self.user_employee).message_needaction_counter
na_emp2_base = self.group_pigs.sudo().message_needaction_counter
# needaction use Inbox notification
(self.user_employee | self.user_admin).write({'notification_type': 'inbox'})
self.group_pigs.message_post(body='Test', message_type='comment', subtype='mail.mt_comment', partner_ids=[self.user_employee.partner_id.id])
na_emp1_base = self.test_pigs.sudo(self.user_employee).message_needaction_counter
na_emp2_base = self.test_pigs.sudo().message_needaction_counter
na_emp1_new = self.group_pigs.sudo(self.user_employee).message_needaction_counter
na_emp2_new = self.group_pigs.sudo().message_needaction_counter
self.test_pigs.message_post(body='Test', message_type='comment', subtype='mail.mt_comment', partner_ids=[self.user_employee.partner_id.id])
na_emp1_new = self.test_pigs.sudo(self.user_employee).message_needaction_counter
na_emp2_new = self.test_pigs.sudo().message_needaction_counter
self.assertEqual(na_emp1_new, na_emp1_base + 1)
self.assertEqual(na_emp2_new, na_emp2_base)
@@ -41,45 +44,45 @@ class TestMessagePost(TestMail):
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_post_no_subscribe_author(self):
original = self.group_pigs.message_follower_ids
self.group_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True}).message_post(
original = self.test_pigs.message_follower_ids
self.test_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True}).message_post(
body='Test Body', message_type='comment', subtype='mt_comment')
self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id'))
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id'))
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
# TODO : the author of a message post on mail.channel should not be added as follower
# TODO : the author of a message post on mail.test should not be added as follower
# @mute_logger('odoo.addons.mail.models.mail_mail')
# def test_post_subscribe_author(self):
# original = self.group_pigs.message_follower_ids
# self.group_pigs.sudo(self.user_employee).message_post(
# original = self.test_pigs.message_follower_ids
# self.test_pigs.sudo(self.user_employee).message_post(
# body='Test Body', message_type='comment', subtype='mt_comment')
# self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id') | self.user_employee.partner_id)
# self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
# self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id') | self.user_employee.partner_id)
# self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_post_no_subscribe_recipients(self):
original = self.group_pigs.message_follower_ids
self.group_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True}).message_post(
original = self.test_pigs.message_follower_ids
self.test_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True}).message_post(
body='Test Body', message_type='comment', subtype='mt_comment', partner_ids=[(4, self.partner_1.id), (4, self.partner_2.id)])
self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id'))
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id'))
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_post_subscribe_recipients(self):
original = self.group_pigs.message_follower_ids
self.group_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True, 'mail_post_autofollow': True}).message_post(
original = self.test_pigs.message_follower_ids
self.test_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True, 'mail_post_autofollow': True}).message_post(
body='Test Body', message_type='comment', subtype='mt_comment', partner_ids=[(4, self.partner_1.id), (4, self.partner_2.id)])
self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id') | self.partner_1 | self.partner_2)
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id') | self.partner_1 | self.partner_2)
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_post_subscribe_recipients_partial(self):
original = self.group_pigs.message_follower_ids
self.group_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True, 'mail_post_autofollow': True, 'mail_post_autofollow_partner_ids': [self.partner_2.id]}).message_post(
original = self.test_pigs.message_follower_ids
self.test_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True, 'mail_post_autofollow': True, 'mail_post_autofollow_partner_ids': [self.partner_2.id]}).message_post(
body='Test Body', message_type='comment', subtype='mt_comment', partner_ids=[(4, self.partner_1.id), (4, self.partner_2.id)])
self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id') | self.partner_2)
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), original.mapped('partner_id') | self.partner_2)
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), original.mapped('channel_id'))
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_post_notifications(self):
@@ -97,11 +100,11 @@ class TestMessagePost(TestMail):
'name': 'Attach2', 'datas_fname': 'Attach2',
'datas': 'bWlncmF0aW9uIHRlc3Q=',
'res_model': 'mail.compose.message', 'res_id': 0})
# partner_2 does not want to receive notification email
self.partner_2.write({'notify_email': 'none'})
self.user_admin.write({'notify_email': 'always'})
self.user_admin.write({'notification_type': 'email'})
# subscribe second employee to the group to test notifications
self.group_pigs.message_subscribe_users(user_ids=[self.env.user.id])
self.test_pigs.message_subscribe_users(user_ids=[self.env.user.id])
# use aliases
_domain = 'schlouby.fr'
@@ -109,7 +112,7 @@ class TestMessagePost(TestMail):
self.env['ir.config_parameter'].set_param('mail.catchall.domain', _domain)
self.env['ir.config_parameter'].set_param('mail.catchall.alias', _catchall)
msg = self.group_pigs.sudo(self.user_employee).message_post(
msg = self.test_pigs.sudo(self.user_employee).message_post(
body=_body, subject=_subject, partner_ids=[self.partner_1.id, self.partner_2.id],
attachment_ids=[_attach_1.id, _attach_2.id], attachments=_attachments,
message_type='comment', subtype='mt_comment')
@@ -122,9 +125,9 @@ class TestMessagePost(TestMail):
self.assertEqual(msg.channel_ids, self.env['mail.channel'])
# attachments
self.assertEqual(set(msg.attachment_ids.mapped('res_model')), set(['mail.channel']),
'message_post: all atttachments should be linked to the mail.channel model')
self.assertEqual(set(msg.attachment_ids.mapped('res_id')), set([self.group_pigs.id]),
self.assertEqual(set(msg.attachment_ids.mapped('res_model')), set(['mail.test']),
'message_post: all atttachments should be linked to the mail.test model')
self.assertEqual(set(msg.attachment_ids.mapped('res_id')), set([self.test_pigs.id]),
'message_post: all atttachments should be linked to the pigs group')
self.assertEqual(set([x.decode('base64') for x in msg.attachment_ids.mapped('datas')]),
set(['migration test', _attachments[0][1], _attachments[1][1]]))
@@ -134,17 +137,18 @@ class TestMessagePost(TestMail):
self.assertFalse(self.env['mail.mail'].search([('mail_message_id', '=', msg.message_id)]),
'message_post: mail.mail notifications should have been auto-deleted')
# notification emails: followers + recipients - notify_email=none (partner_2) - author (user_employee)
# notification emails: followers + recipients - author (user_employee)
self.assertEqual(set(m['email_from'] for m in self._mails),
set(['%s <%s>' % (self.user_employee.name, self.user_employee.email)]),
'message_post: notification email wrong email_from: should use sender email')
self.assertEqual(set(m['email_to'][0] for m in self._mails),
set(['%s <%s>' % (self.partner_1.name, self.partner_1.email),
'%s <%s>' % (self.partner_2.name, self.partner_2.email),
'%s <%s>' % (self.env.user.name, self.env.user.email)]))
self.assertFalse(any(len(m['email_to']) != 1 for m in self._mails),
'message_post: notification email should be sent to one partner at a time')
self.assertEqual(set(m['reply_to'] for m in self._mails),
set(['%s %s <%s@%s>' % (self.env.user.company_id.name, self.group_pigs.name, self.group_pigs.alias_name, _domain)]),
set(['%s %s <%s@%s>' % (self.env.user.company_id.name, self.test_pigs.name, self.test_pigs.alias_name, _domain)]),
'message_post: notification email should use group aliases and data for reply to')
self.assertTrue(all(_subject in m['subject'] for m in self._mails))
self.assertTrue(all(_body in m['body'] for m in self._mails))
@@ -162,36 +166,48 @@ class TestMessagePost(TestMail):
self.env['ir.config_parameter'].set_param('mail.catchall.domain', _domain)
self.env['ir.config_parameter'].set_param('mail.catchall.alias', _catchall)
parent_msg = self.group_pigs.sudo(self.user_employee).message_post(
parent_msg = self.test_pigs.sudo(self.user_employee).message_post(
body=_body, subject=_subject,
message_type='comment', subtype='mt_comment')
self.assertEqual(parent_msg.partner_ids, self.env['res.partner'])
msg = self.group_pigs.sudo(self.user_employee).message_post(
msg = self.test_pigs.sudo(self.user_employee).message_post(
body=_body, subject=_subject, partner_ids=[self.partner_1.id],
message_type='comment', subtype='mt_comment', parent_id=parent_msg.id)
self.assertEqual(msg.parent_id.id, parent_msg.id)
self.assertEqual(msg.partner_ids, self.partner_1)
# self.assertEqual(parent_msg.partner_ids, self.partner_1) # TDE FIXME: to check
self.assertTrue(all('openerp-%d-mail.channel' % self.group_pigs.id in m['references'] for m in self._mails))
new_msg = self.group_pigs.sudo(self.user_employee).message_post(
self.assertTrue(all('openerp-%d-mail.test' % self.test_pigs.id in m['references'] for m in self._mails))
new_msg = self.test_pigs.sudo(self.user_employee).message_post(
body=_body, subject=_subject,
message_type='comment', subtype='mt_comment', parent_id=msg.id)
self.assertEqual(new_msg.parent_id.id, parent_msg.id, 'message_post: flatten error')
self.assertFalse(new_msg.partner_ids)
def test_post_portal(self):
self.test_pigs.message_subscribe((self.partner_1 | self.user_employee.partner_id).ids)
new_msg = self.test_pigs.sudo(self.user_portal).message_post(
body='<p>Test</p>', subject='Subject',
message_type='comment', subtype='mt_comment')
self.assertEqual(new_msg.sudo().needaction_partner_ids, (self.partner_1 | self.user_employee.partner_id))
self.assertEqual(
set(m['email_to'][0] for m in self._mails),
set(['%s <%s>' % (self.partner_1.name, self.partner_1.email),
'%s <%s>' % (self.user_employee.name, self.user_employee.email)]))
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_post_internal(self):
self.group_pigs.message_subscribe_users([self.user_admin.id])
msg = self.group_pigs.sudo(self.user_employee).message_post(
self.test_pigs.message_subscribe_users([self.user_admin.id])
msg = self.test_pigs.sudo(self.user_employee).message_post(
body='My Body', subject='My Subject',
message_type='comment', subtype='mt_note')
self.assertEqual(msg.partner_ids, self.env['res.partner'])
self.assertEqual(msg.needaction_partner_ids, self.env['res.partner'])
self.assertEqual(self.group_pigs.message_ids, msg)
self.assertEqual(self.test_pigs.message_ids, msg)
self.format_and_process(
MAIL_TEMPLATE_PLAINTEXT,
@@ -199,7 +215,7 @@ class TestMessagePost(TestMail):
msg_id='<1198923581.41972151344608186800.JavaMail.diff1@agrolait.com>',
to='not_my_businesss@example.com',
extra='In-Reply-To:\r\n\t%s\n' % msg.message_id)
reply = self.group_pigs.message_ids - msg
reply = self.test_pigs.message_ids - msg
self.assertTrue(reply)
self.assertEqual(reply.subtype_id, self.env.ref('mail.mt_note'))
self.assertEqual(reply.needaction_partner_ids, self.user_employee.partner_id)
@@ -208,30 +224,30 @@ class TestMessagePost(TestMail):
def test_message_compose(self):
composer = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'comment',
'default_model': 'mail.channel',
'default_res_id': self.group_pigs.id,
'default_model': 'mail.test',
'default_res_id': self.test_pigs.id,
}).sudo(self.user_employee).create({
'body': '<p>Test Body</p>',
'partner_ids': [(4, self.partner_1.id), (4, self.partner_2.id)]
})
self.assertEqual(composer.composition_mode, 'comment')
self.assertEqual(composer.model, 'mail.channel')
self.assertEqual(composer.subject, 'Re: %s' % self.group_pigs.name)
self.assertEqual(composer.record_name, self.group_pigs.name)
self.assertEqual(composer.model, 'mail.test')
self.assertEqual(composer.subject, 'Re: %s' % self.test_pigs.name)
self.assertEqual(composer.record_name, self.test_pigs.name)
composer.send_mail()
message = self.group_pigs.message_ids[0]
message = self.test_pigs.message_ids[0]
composer = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'comment',
'default_res_id': self.group_pigs.id,
'default_res_id': self.test_pigs.id,
'default_parent_id': message.id
}).sudo(self.user_employee).create({})
self.assertEqual(composer.model, 'mail.channel')
self.assertEqual(composer.res_id, self.group_pigs.id)
self.assertEqual(composer.model, 'mail.test')
self.assertEqual(composer.res_id, self.test_pigs.id)
self.assertEqual(composer.parent_id, message)
self.assertEqual(composer.subject, 'Re: %s' % self.group_pigs.name)
self.assertEqual(composer.subject, 'Re: %s' % self.test_pigs.name)
# TODO: test attachments ?
@@ -239,9 +255,9 @@ class TestMessagePost(TestMail):
def test_message_compose_mass_mail(self):
composer = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'mass_mail',
'default_model': 'mail.channel',
'default_model': 'mail.test',
'default_res_id': False,
'active_ids': [self.group_pigs.id, self.group_public.id]
'active_ids': [self.test_pigs.id, self.test_public.id]
}).sudo(self.user_employee).create({
'subject': 'Testing ${object.name}',
'body': '<p>${object.description}</p>',
@@ -249,7 +265,7 @@ class TestMessagePost(TestMail):
})
composer.with_context({
'default_res_id': -1,
'active_ids': [self.group_pigs.id, self.group_public.id]
'active_ids': [self.test_pigs.id, self.test_public.id]
}).send_mail()
# check mail_mail
@@ -258,19 +274,19 @@ class TestMessagePost(TestMail):
self.assertEqual(mail.recipient_ids, self.partner_1 | self.partner_2,
'compose wizard: mail_mail mass mailing: mail.mail in mass mail incorrect recipients')
# check message on group_pigs
message1 = self.group_pigs.message_ids[0]
self.assertEqual(message1.subject, 'Testing %s' % self.group_pigs.name)
self.assertEqual(message1.body, '<p>%s</p>' % self.group_pigs.description)
# check message on test_pigs
message1 = self.test_pigs.message_ids[0]
self.assertEqual(message1.subject, 'Testing %s' % self.test_pigs.name)
self.assertEqual(message1.body, '<p>%s</p>' % self.test_pigs.description)
# check message on group_public
message1 = self.group_public.message_ids[0]
self.assertEqual(message1.subject, 'Testing %s' % self.group_public.name)
self.assertEqual(message1.body, '<p>%s</p>' % self.group_public.description)
# check message on test_public
message1 = self.test_public.message_ids[0]
self.assertEqual(message1.subject, 'Testing %s' % self.test_public.name)
self.assertEqual(message1.body, '<p>%s</p>' % self.test_public.description)
# # Test: Pigs and Bird did receive their message
# # check logged messages
# message1 = group_pigs.message_ids[0]
# message1 = test_pigs.message_ids[0]
# message2 = group_bird.message_ids[0]
# # Test: Pigs and Bird did receive their message
# messages = self.MailMessage.search([], limit=2)
@@ -283,8 +299,8 @@ class TestMessagePost(TestMail):
# self.assertIn(message2.id, messages.ids, 'compose wizard: Bird did not receive its mass mailing message')
# check followers ?
# Test: mail.channel followers: author not added as follower in mass mail mode
# self.assertEqual(set(group_pigs.message_follower_ids.ids), set([self.partner_admin_id, p_b.id, p_c.id, p_d.id]),
# Test: mail.test followers: author not added as follower in mass mail mode
# self.assertEqual(set(test_pigs.message_follower_ids.ids), set([self.partner_admin_id, p_b.id, p_c.id, p_d.id]),
# 'compose wizard: mail_post_autofollow and mail_create_nosubscribe context keys not correctly taken into account')
# self.assertEqual(set(group_bird.message_follower_ids.ids), set([self.partner_admin_id]),
# 'compose wizard: mail_post_autofollow and mail_create_nosubscribe context keys not correctly taken into account')
@@ -293,31 +309,31 @@ class TestMessagePost(TestMail):
def test_message_compose_mass_mail_active_domain(self):
self.env['mail.compose.message'].with_context({
'default_composition_mode': 'mass_mail',
'default_model': 'mail.channel',
'default_model': 'mail.test',
'default_use_active_domain': True,
'active_ids': [self.group_pigs.id],
'active_domain': [('name', 'in', ['%s' % self.group_pigs.name, '%s' % self.group_public.name])],
'active_ids': [self.test_pigs.id],
'active_domain': [('name', 'in', ['%s' % self.test_pigs.name, '%s' % self.test_public.name])],
}).sudo(self.user_employee).create({
'subject': 'From Composer Test',
'body': '${object.description}',
}).send_mail()
self.assertEqual(self.group_pigs.message_ids[0].subject, 'From Composer Test')
self.assertEqual(self.group_public.message_ids[0].subject, 'From Composer Test')
self.assertEqual(self.test_pigs.message_ids[0].subject, 'From Composer Test')
self.assertEqual(self.test_public.message_ids[0].subject, 'From Composer Test')
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_message_compose_mass_mail_no_active_domain(self):
self.env['mail.compose.message'].with_context({
'default_composition_mode': 'mass_mail',
'default_model': 'mail.channel',
'default_model': 'mail.test',
'default_use_active_domain': False,
'active_ids': [self.group_pigs.id],
'active_domain': [('name', 'in', ['%s' % self.group_pigs.name, '%s' % self.group_public.name])],
'active_ids': [self.test_pigs.id],
'active_domain': [('name', 'in', ['%s' % self.test_pigs.name, '%s' % self.test_public.name])],
}).sudo(self.user_employee).create({
'subject': 'From Composer Test',
'body': '${object.description}',
}).send_mail()
self.assertEqual(self.group_pigs.message_ids[0].subject, 'From Composer Test')
self.assertFalse(self.group_public.message_ids.ids)
self.assertEqual(self.test_pigs.message_ids[0].subject, 'From Composer Test')
self.assertFalse(self.test_public.message_ids.ids)
+51 -50
View File
@@ -11,21 +11,21 @@ class TestMailFollowers(TestMail):
def setUp(self):
super(TestMailFollowers, self).setUp()
Subtype = self.env['mail.message.subtype']
self.mt_mg_def = Subtype.create({'name': 'mt_mg_def', 'default': True, 'res_model': 'mail.channel'})
self.mt_mg_def = Subtype.create({'name': 'mt_mg_def', 'default': True, 'res_model': 'mail.test'})
self.mt_cl_def = Subtype.create({'name': 'mt_cl_def', 'default': True, 'res_model': 'crm.lead'})
self.mt_al_def = Subtype.create({'name': 'mt_al_def', 'default': True, 'res_model': False})
self.mt_mg_nodef = Subtype.create({'name': 'mt_mg_nodef', 'default': False, 'res_model': 'mail.channel'})
self.mt_mg_nodef = Subtype.create({'name': 'mt_mg_nodef', 'default': False, 'res_model': 'mail.test'})
self.mt_al_nodef = Subtype.create({'name': 'mt_al_nodef', 'default': False, 'res_model': False})
self.default_group_subtypes = Subtype.search([('default', '=', True), '|', ('res_model', '=', 'mail.channel'), ('res_model', '=', False)])
self.default_group_subtypes = Subtype.search([('default', '=', True), '|', ('res_model', '=', 'mail.test'), ('res_model', '=', False)])
def test_m2o_command_new(self):
test_channel = self.env['mail.channel'].create({'name': 'Test'})
groups = self.group_pigs | self.group_public
groups = self.test_pigs | self.test_public
generic, specific = self.env['mail.followers']._add_follower_command(
'mail.channel', groups.ids,
'mail.test', groups.ids,
{self.user_employee.partner_id.id: [self.mt_mg_nodef.id]},
{test_channel.id: [self.mt_al_nodef.id]})
mail_channel_model_id = self.env['ir.model']._get('mail.channel').id
mail_channel_model_id = self.env['ir.model']._get('mail.test').id
self.assertFalse(specific)
self.assertEqual(len(generic), 2)
@@ -40,11 +40,11 @@ class TestMailFollowers(TestMail):
def test_m2o_command_update_selective(self):
test_channel = self.env['mail.channel'].create({'name': 'Test'})
mail_channel_model_id = self.env['ir.model']._get('mail.channel').id
groups = self.group_pigs | self.group_public
self.env['mail.followers'].create({'partner_id': self.user_employee.partner_id.id, 'res_model_id': mail_channel_model_id, 'res_id': self.group_pigs.id})
mail_channel_model_id = self.env['ir.model']._get('mail.test').id
groups = self.test_pigs | self.test_public
self.env['mail.followers'].create({'partner_id': self.user_employee.partner_id.id, 'res_model_id': mail_channel_model_id, 'res_id': self.test_pigs.id})
generic, specific = self.env['mail.followers']._add_follower_command(
'mail.channel', groups.ids,
'mail.test', groups.ids,
{self.user_employee.partner_id.id: [self.mt_mg_nodef.id]},
{test_channel.id: False},
force=False)
@@ -55,74 +55,74 @@ class TestMailFollowers(TestMail):
self.assertEqual(generic[0][2]['channel_id'], test_channel.id)
self.assertEqual(set(generic[0][2]['subtype_ids'][0][2]), set(self.default_group_subtypes.ids))
self.assertEqual(specific.keys(), [self.group_public.id])
self.assertEqual(specific[self.group_public.id][0][2]['res_model_id'], mail_channel_model_id)
self.assertEqual(specific[self.group_public.id][0][2]['partner_id'], self.user_employee.partner_id.id)
self.assertEqual(set(specific[self.group_public.id][0][2]['subtype_ids'][0][2]), set([self.mt_mg_nodef.id]))
self.assertEqual(specific.keys(), [self.test_public.id])
self.assertEqual(specific[self.test_public.id][0][2]['res_model_id'], mail_channel_model_id)
self.assertEqual(specific[self.test_public.id][0][2]['partner_id'], self.user_employee.partner_id.id)
self.assertEqual(set(specific[self.test_public.id][0][2]['subtype_ids'][0][2]), set([self.mt_mg_nodef.id]))
def test_message_is_follower(self):
qty_followed_before = len(self.group_pigs.sudo(self.user_employee).search([('message_is_follower', '=', True)]))
self.assertFalse(self.group_pigs.sudo(self.user_employee).message_is_follower)
self.group_pigs.message_subscribe_users(user_ids=[self.user_employee.id])
qty_followed_after = len(self.group_pigs.sudo(self.user_employee).search([('message_is_follower', '=', True)]))
self.assertTrue(self.group_pigs.sudo(self.user_employee).message_is_follower)
qty_followed_before = len(self.test_pigs.sudo(self.user_employee).search([('message_is_follower', '=', True)]))
self.assertFalse(self.test_pigs.sudo(self.user_employee).message_is_follower)
self.test_pigs.message_subscribe_users(user_ids=[self.user_employee.id])
qty_followed_after = len(self.test_pigs.sudo(self.user_employee).search([('message_is_follower', '=', True)]))
self.assertTrue(self.test_pigs.sudo(self.user_employee).message_is_follower)
self.assertEqual(qty_followed_before + 1, qty_followed_after)
def test_followers_subtypes_default(self):
self.group_pigs.message_subscribe_users(user_ids=[self.user_employee.id])
self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), self.user_employee.partner_id)
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), self.env['mail.channel'])
self.test_pigs.message_subscribe_users(user_ids=[self.user_employee.id])
self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), self.user_employee.partner_id)
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), self.env['mail.channel'])
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.channel'),
('res_id', '=', self.group_pigs.id),
('res_model', '=', 'mail.test'),
('res_id', '=', self.test_pigs.id),
('partner_id', '=', self.user_employee.partner_id.id)])
self.assertEqual(len(follower), 1)
self.assertEqual(follower.subtype_ids, self.default_group_subtypes)
def test_followers_subtypes_default_internal(self):
mt_mg_def_int = self.env['mail.message.subtype'].create({'name': 'mt_mg_def', 'default': True, 'res_model': 'mail.channel', 'internal': True})
self.group_pigs.message_subscribe_users(user_ids=[self.user_employee.id])
mt_mg_def_int = self.env['mail.message.subtype'].create({'name': 'mt_mg_def', 'default': True, 'res_model': 'mail.test', 'internal': True})
self.test_pigs.message_subscribe_users(user_ids=[self.user_employee.id])
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.channel'),
('res_id', '=', self.group_pigs.id),
('res_model', '=', 'mail.test'),
('res_id', '=', self.test_pigs.id),
('partner_id', '=', self.user_employee.partner_id.id)])
self.assertEqual(follower.subtype_ids, self.default_group_subtypes | mt_mg_def_int)
self.group_pigs.message_subscribe_users(user_ids=[self.user_portal.id])
self.test_pigs.message_subscribe_users(user_ids=[self.user_portal.id])
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.channel'),
('res_id', '=', self.group_pigs.id),
('res_model', '=', 'mail.test'),
('res_id', '=', self.test_pigs.id),
('partner_id', '=', self.user_portal.partner_id.id)])
self.assertEqual(follower.subtype_ids, self.default_group_subtypes.filtered(lambda subtype: not subtype.internal))
def test_followers_subtypes_specified(self):
self.group_pigs.sudo(self.user_employee).message_subscribe_users(subtype_ids=[self.mt_mg_nodef.id])
self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), self.user_employee.partner_id)
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), self.env['mail.channel'])
self.test_pigs.sudo(self.user_employee).message_subscribe_users(subtype_ids=[self.mt_mg_nodef.id])
self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), self.user_employee.partner_id)
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), self.env['mail.channel'])
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.channel'),
('res_id', '=', self.group_pigs.id),
('res_model', '=', 'mail.test'),
('res_id', '=', self.test_pigs.id),
('partner_id', '=', self.user_employee.partner_id.id)])
self.assertEqual(len(follower), 1)
self.assertEqual(follower.subtype_ids, self.mt_mg_nodef)
def test_followers_multiple_subscription(self):
self.group_pigs.sudo(self.user_employee).message_subscribe_users(subtype_ids=[self.mt_mg_nodef.id])
self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), self.user_employee.partner_id)
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), self.env['mail.channel'])
self.test_pigs.sudo(self.user_employee).message_subscribe_users(subtype_ids=[self.mt_mg_nodef.id])
self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), self.user_employee.partner_id)
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), self.env['mail.channel'])
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.channel'),
('res_id', '=', self.group_pigs.id),
('res_model', '=', 'mail.test'),
('res_id', '=', self.test_pigs.id),
('partner_id', '=', self.user_employee.partner_id.id)])
self.assertEqual(len(follower), 1)
self.assertEqual(follower.subtype_ids, self.mt_mg_nodef)
self.group_pigs.sudo(self.user_employee).message_subscribe_users(subtype_ids=[self.mt_mg_nodef.id, self.mt_al_nodef.id])
self.assertEqual(self.group_pigs.message_follower_ids.mapped('partner_id'), self.user_employee.partner_id)
self.assertEqual(self.group_pigs.message_follower_ids.mapped('channel_id'), self.env['mail.channel'])
self.test_pigs.sudo(self.user_employee).message_subscribe_users(subtype_ids=[self.mt_mg_nodef.id, self.mt_al_nodef.id])
self.assertEqual(self.test_pigs.message_follower_ids.mapped('partner_id'), self.user_employee.partner_id)
self.assertEqual(self.test_pigs.message_follower_ids.mapped('channel_id'), self.env['mail.channel'])
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.channel'),
('res_id', '=', self.group_pigs.id),
('res_model', '=', 'mail.test'),
('res_id', '=', self.test_pigs.id),
('partner_id', '=', self.user_employee.partner_id.id)])
self.assertEqual(len(follower), 1)
self.assertEqual(follower.subtype_ids, self.mt_mg_nodef | self.mt_al_nodef)
@@ -131,13 +131,14 @@ class TestMailFollowers(TestMail):
"""Test that a follower cannot suffer from dissociative identity disorder.
It cannot be both a partner and a channel.
"""
test_channel = self.env['mail.channel'].create({
test_record = self.env['mail.channel'].create({
'name': 'I used to be schizo, but now we are alright.'
})
test_channel = self.env['mail.channel'].create({'name': 'Follower Channel'})
with self.assertRaises(IntegrityError):
self.env['mail.followers'].create({
'res_model_id': self.env['ir.model']._get('mail.channel').id,
'res_id': test_channel.id,
'res_model_id': self.env['ir.model']._get('mail.test').id,
'res_id': test_record.id,
'partner_id': self.user_employee.partner_id.id,
'channel_id': self.group_pigs.id,
'channel_id': test_channel.id,
})
+63 -55
View File
@@ -290,30 +290,31 @@ class TestMailgateway(TestMail):
def setUp(self):
super(TestMailgateway, self).setUp()
# groups@.. will cause the creation of new mail.channels
self.mail_channel_model = self.env['ir.model']._get('mail.channel')
mail_test_model = self.env['ir.model']._get('mail.test')
mail_channel_model = self.env['ir.model']._get('mail.channel')
# groups@.. will cause the creation of new mail.test
self.alias = self.env['mail.alias'].create({
'alias_name': 'groups',
'alias_user_id': False,
'alias_model_id': self.mail_channel_model.id,
'alias_model_id': mail_test_model.id,
'alias_contact': 'everyone'})
# test@.. will cause the creation of new mail.test
self.mail_test_model = self.env['ir.model']._get('mail.test')
self.alias_2 = self.env['mail.alias'].create({
'alias_name': 'test',
'alias_user_id': False,
'alias_model_id': self.mail_test_model.id,
'alias_model_id': mail_channel_model.id,
'alias_contact': 'everyone'})
# Set a first message on public group to test update and hierarchy
self.fake_email = self.env['mail.message'].create({
'model': 'mail.channel',
'res_id': self.group_public.id,
'model': 'mail.test',
'res_id': self.test_public.id,
'subject': 'Public Discussion',
'message_type': 'email',
'author_id': self.partner_1.id,
'message_id': '<123456-openerp-%s-mail.channel@%s>' % (self.group_public.id, socket.gethostname()),
'message_id': '<123456-openerp-%s-mail.test@%s>' % (self.test_public.id, socket.gethostname()),
})
@mute_logger('odoo.addons.mail.models.mail_thread')
@@ -361,7 +362,7 @@ class TestMailgateway(TestMail):
new_groups = self.format_and_process(MAIL_TEMPLATE, subject='My Frogs', to='groups@example.com, other@gmail.com')
# Test: one group created by mailgateway administrator
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.channel should have been created')
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.test should have been created')
res = new_groups.get_metadata()[0].get('create_uid') or [None]
self.assertEqual(res[0], self.env.uid,
'message_process: group should have been created by uid as alias_user_id is False on the alias')
@@ -390,7 +391,7 @@ class TestMailgateway(TestMail):
new_groups = self.format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
# Test: one group created by mailgateway administrator
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.channel should have been created')
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.test should have been created')
res = new_groups.get_metadata()[0].get('create_uid') or [None]
self.assertEqual(res[0], self.user_employee.id,
'message_process: group should have been created by alias_user_id')
@@ -418,7 +419,7 @@ class TestMailgateway(TestMail):
self.assertIn('Valid Lelitre <valid.lelitre@agrolait.com>', new_groups.message_ids[0].email_from,
'message_process: recognized email -> email_from')
# TODO : the author of a message post on mail.channel should not be added as follower
# TODO : the author of a message post on mail.test should not be added as follower
# FAIL ON recognized email -> added as follower')
# self.assertEqual(new_groups.message_partner_ids, self.partner_1,
# 'message_process: recognized email -> added as follower')
@@ -446,8 +447,8 @@ class TestMailgateway(TestMail):
""" Incoming email from unknown partner / not follower partner on a Followers only alias -> bounce """
self.alias.write({
'alias_contact': 'followers',
'alias_parent_model_id': self.mail_channel_model.id,
'alias_parent_thread_id': self.group_pigs.id})
'alias_parent_model_id': self.env['ir.model']._get('mail.test').id,
'alias_parent_thread_id': self.test_pigs.id})
# Test: unknown on followers alias -> bounce
new_groups = self.format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
@@ -469,7 +470,7 @@ class TestMailgateway(TestMail):
new_groups = self.format_and_process(MAIL_TEMPLATE, email_from='Valid Lelitre <valid.lelitre@agrolait.com>', to='groups@example.com, valid.other@gmail.com')
# Test: one group created by alias user
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.channel should have been created')
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.test should have been created')
# Test: one message that is the incoming email
self.assertEqual(len(new_groups.message_ids), 1,
@@ -480,20 +481,20 @@ class TestMailgateway(TestMail):
""" Incoming email from a parent document follower on a Followers only alias -> ok """
self.alias.write({
'alias_contact': 'followers',
'alias_parent_model_id': self.mail_channel_model.id,
'alias_parent_thread_id': self.group_pigs.id})
self.group_pigs.message_subscribe(partner_ids=[self.partner_1.id])
'alias_parent_model_id': self.env['ir.model']._get('mail.test').id,
'alias_parent_thread_id': self.test_pigs.id})
self.test_pigs.message_subscribe(partner_ids=[self.partner_1.id])
new_groups = self.format_and_process(MAIL_TEMPLATE, email_from='Valid Lelitre <valid.lelitre@agrolait.com>', to='groups@example.com, other6@gmail.com')
# Test: one group created by Raoul (or Sylvie maybe, if we implement it)
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.channel should have been created')
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.test should have been created')
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models', 'odoo.addons.mail.models.mail_mail')
def test_message_process_alias_update(self):
""" Incoming email update discussion + notification email """
self.alias.write({'alias_force_thread_id': self.group_public.id})
self.alias.write({'alias_force_thread_id': self.test_public.id})
self.group_public.message_subscribe(partner_ids=[self.partner_1.id])
self.test_public.message_subscribe(partner_ids=[self.partner_1.id])
new_groups = self.format_and_process(
MAIL_TEMPLATE, email_from='valid.other@gmail.com',
msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>',
@@ -502,20 +503,20 @@ class TestMailgateway(TestMail):
# Test: no new group + new message
self.assertEqual(len(new_groups), 0,
'message_process: reply on Frogs should not have created a new group with new subject')
self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.test_public.message_ids), 2, 'message_process: group should contain one new message')
# Test: sent emails: 1 (Sylvie copy of the incoming email)
self.assertEqual(len(self._mails), 1,
'message_process: one email should have been generated')
self.assertIn('valid.lelitre@agrolait.com', self._mails[0].get('email_to')[0],
'message_process: email should be sent to Sylvie')
# TODO : the author of a message post on mail.channel should not be added as follower
# TODO : the author of a message post on mail.test should not be added as follower
# FAIL ON 'message_process: after reply, group should have 2 followers') ` AssertionError: res.partner(104,) != res.partner(104, 105) : message_process: after reply, group should have 2 followers
# Test: author (and not recipient) added as follower
# self.assertEqual(self.group_public.message_partner_ids, self.partner_1 | self.partner_2,
# self.assertEqual(self.test_public.message_partner_ids, self.partner_1 | self.partner_2,
# 'message_process: after reply, group should have 2 followers')
# self.assertEqual(self.group_public.message_channel_ids, self.env['mail.channel'],
# self.assertEqual(self.test_public.message_channel_ids, self.env['mail.test'],
# 'message_process: after reply, group should have 2 followers (0 channels)')
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models')
@@ -527,7 +528,7 @@ class TestMailgateway(TestMail):
to='erroneous@example.com>', subject='Re: news',
extra='In-Reply-To:\r\n\t%s\n' % self.fake_email.message_id)
self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.test_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one')
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models')
@@ -538,7 +539,7 @@ class TestMailgateway(TestMail):
extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id,
msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>')
self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.test_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one')
def test_message_process_references_external(self):
@@ -552,10 +553,10 @@ class TestMailgateway(TestMail):
extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id,
msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>')
self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.test_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one')
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models')
# @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models')
def test_message_process_references_forward(self):
""" Incoming email using references but with alias forward should not go into references destination """
res_test = self.format_and_process(
@@ -563,9 +564,9 @@ class TestMailgateway(TestMail):
subject='My Dear Forward',
extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id,
msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>',
target_model='mail.test')
target_model='mail.channel')
self.assertEqual(len(self.group_public.message_ids), 1, 'message_process: group should not contain new message')
self.assertEqual(len(self.test_public.message_ids), 1, 'message_process: group should not contain new message')
self.assertEqual(len(self.fake_email.child_ids), 0, 'message_process: original email should not contain childs')
self.assertEqual(res_test.name, 'My Dear Forward')
self.assertEqual(len(res_test.message_ids), 1)
@@ -580,7 +581,7 @@ class TestMailgateway(TestMail):
msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>',
target_model='mail.test')
self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.test_public.message_ids), 2, 'message_process: group should contain one new message')
self.assertEqual(len(self.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one')
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models')
@@ -590,7 +591,7 @@ class TestMailgateway(TestMail):
self.format_and_process,
MAIL_TEMPLATE, email_from='valid.lelitre@agrolait.com',
to='noone@example.com', subject='spam',
extra='In-Reply-To: <12321321-openerp-%d-mail.channel@%s>' % (self.group_public.id, socket.gethostname()),
extra='In-Reply-To: <12321321-openerp-%d-mail.test@%s>' % (self.test_public.id, socket.gethostname()),
msg_id='<1198923581.41972151344608186802.JavaMail.diff1@agrolait.com>')
# when 6.1 messages are present, compat mode is available
@@ -603,7 +604,7 @@ class TestMailgateway(TestMail):
MAIL_TEMPLATE, email_from='other5@gmail.com',
msg_id='<1.2.JavaMail.new@agrolait.com>',
to='noone@example.com>', subject='spam',
extra='In-Reply-To: <12321321-openerp-%d-mail.channel@%s>' % (self.group_public.id, socket.gethostname()))
extra='In-Reply-To: <12321321-openerp-%d-mail.test@%s>' % (self.test_public.id, socket.gethostname()))
# 3''. 6.1 compat mode should not work if hostname does not match!
# Odoo 10 update: compat mode has been removed and should not work anymore and does not depend from hostname
@@ -612,16 +613,16 @@ class TestMailgateway(TestMail):
MAIL_TEMPLATE, email_from='other5@gmail.com',
msg_id='<1.3.JavaMail.new@agrolait.com>',
to='noone@example.com>', subject='spam',
extra='In-Reply-To: <12321321-openerp-%d-mail.channel@neighbor.com>' % self.group_public.id)
extra='In-Reply-To: <12321321-openerp-%d-mail.test@neighbor.com>' % self.test_public.id)
# Test created messages
self.assertEqual(len(self.group_public.message_ids), 1)
self.assertEqual(len(self.group_public.message_ids[0].child_ids), 0)
self.assertEqual(len(self.test_public.message_ids), 1)
self.assertEqual(len(self.test_public.message_ids[0].child_ids), 0)
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models')
def test_message_process_duplicate(self):
""" Duplicate emails (same message_id) are not processed """
self.alias.write({'alias_force_thread_id': self.group_public.id,})
self.alias.write({'alias_force_thread_id': self.test_public.id,})
# Post a base message
frog_groups = self.format_and_process(
@@ -639,7 +640,7 @@ class TestMailgateway(TestMail):
'message_process: reply on Frogs should not have created a new group with new subject')
# Test: no new message
self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: message with already existing message_id should not have been duplicated')
self.assertEqual(len(self.test_public.message_ids), 2, 'message_process: message with already existing message_id should not have been duplicated')
# Test: message_id is still unique
no_of_msg = self.env['mail.message'].search_count([('message_id', 'ilike', '<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>')])
self.assertEqual(no_of_msg, 1,
@@ -651,20 +652,20 @@ class TestMailgateway(TestMail):
from_1 = self.env['res.partner'].create({'name': 'A', 'email': 'from.test@example.com'})
self.format_and_process(MAIL_TEMPLATE, to='public@example.com', msg_id='<1>', email_from='Brice Denisse <from.test@example.com>')
self.assertEqual(self.group_public.message_ids[0].author_id, from_1, 'message_process: email_from -> author_id wrong')
self.group_public.message_unsubscribe([from_1.id])
self.assertEqual(self.test_public.message_ids[0].author_id, from_1, 'message_process: email_from -> author_id wrong')
self.test_public.message_unsubscribe([from_1.id])
from_2 = self.env['res.users'].with_context({'no_reset_password': True}).create({'name': 'B', 'login': 'B', 'email': 'from.test@example.com'})
self.format_and_process(MAIL_TEMPLATE, to='public@example.com', msg_id='<2>', email_from='Brice Denisse <from.test@example.com>')
self.assertEqual(self.group_public.message_ids[0].author_id, from_2.partner_id, 'message_process: email_from -> author_id wrong')
self.group_public.message_unsubscribe([from_2.partner_id.id])
self.assertEqual(self.test_public.message_ids[0].author_id, from_2.partner_id, 'message_process: email_from -> author_id wrong')
self.test_public.message_unsubscribe([from_2.partner_id.id])
from_3 = self.env['res.partner'].create({'name': 'C', 'email': 'from.test@example.com'})
self.group_public.message_subscribe([from_3.id])
self.test_public.message_subscribe([from_3.id])
self.format_and_process(MAIL_TEMPLATE, to='public@example.com', msg_id='<3>', email_from='Brice Denisse <from.test@example.com>')
self.assertEqual(self.group_public.message_ids[0].author_id, from_3, 'message_process: email_from -> author_id wrong')
self.assertEqual(self.test_public.message_ids[0].author_id, from_3, 'message_process: email_from -> author_id wrong')
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models')
def test_message_process_crash_wrong_model(self):
@@ -688,10 +689,10 @@ class TestMailgateway(TestMail):
def test_message_process_fallback(self):
""" Incoming email with model that accepting incoming emails as fallback """
frog_groups = self.format_and_process(
MAIL_TEMPLATE, to='noone@example.com', subject='Spammy', extra='', model='mail.channel',
MAIL_TEMPLATE, to='noone@example.com', subject='Spammy', extra='', model='mail.test',
msg_id='<1198923581.41972151344608186760.JavaMail.new6@agrolait.com>')
self.assertEqual(len(frog_groups), 1,
'message_process: erroneous email but with a fallback model should have created a new mail.channel')
'message_process: erroneous email but with a fallback model should have created a new mail.test')
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models')
def test_message_process_plain_text(self):
@@ -699,7 +700,7 @@ class TestMailgateway(TestMail):
frog_groups = self.format_and_process(
MAIL_TEMPLATE_PLAINTEXT, to='groups@example.com', subject='Frogs Return', extra='',
msg_id='<deadcafe.1337@smtp.agrolait.com>')
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.channel should have been created')
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.test should have been created')
msg = frog_groups.message_ids[0]
# signature recognition -> Sylvie should be in a span
self.assertIn('<pre>\nPlease call me as soon as possible this afternoon!\n<span data-o-mail-quote="1">\n--\nSylvie\n</span></pre>', msg.body,
@@ -712,7 +713,7 @@ class TestMailgateway(TestMail):
# Do: Raoul writes to Bert and Administrator, with a thread_model in context that should not be taken into account
msg1 = self.env['mail.thread'].with_context({
'thread_model': 'mail.channel'
'thread_model': 'mail.test'
}).sudo(self.user_employee).message_post(partner_ids=msg1_pids, subtype='mail.mt_comment')
# Test: message recipients
@@ -733,7 +734,7 @@ class TestMailgateway(TestMail):
msg2 = self.env['mail.message'].search([], limit=1)
# Test: message recipients
self.assertEqual(msg2.author_id, self.partner_1,
'message_post: private discussion: wrong author through mailgatewya based on email')
'message_post: private discussion: wrong author through mailgateway based on email')
self.assertEqual(msg2.partner_ids, self.user_employee.partner_id | self.env.user.partner_id,
'message_post: private discussion: incorrect recipients when replying')
@@ -749,7 +750,7 @@ class TestMailgateway(TestMail):
@mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models', 'odoo.addons.mail.models.mail_mail')
def test_forward_parent_id(self):
msg = self.group_pigs.sudo(self.user_employee).message_post(no_auto_thread=True, subtype='mail.mt_comment')
msg = self.test_pigs.sudo(self.user_employee).message_post(no_auto_thread=True, subtype='mail.mt_comment')
self.assertNotIn(msg.model, msg.message_id)
self.assertNotIn('-%d-' % msg.res_id, msg.message_id)
self.assertIn('reply_to', msg.message_id)
@@ -765,12 +766,16 @@ class TestMailgateway(TestMail):
self.env['mail.thread'].message_process(None, fw_message)
msg_fw = self.env['mail.message'].search([('message_id', '=', fw_msg_id)])
self.assertEqual(len(msg_fw), 1)
channel = self.env['mail.channel'].search([('name', "=", msg_fw.subject)])
channel = self.env['mail.test'].search([('name', "=", msg_fw.subject)])
self.assertEqual(len(channel), 1)
self.assertEqual(msg_fw.model, 'mail.channel')
self.assertEqual(msg_fw.model, 'mail.test')
self.assertFalse(msg_fw.parent_id)
self.assertTrue(msg_fw.res_id == channel.id)
# tmp
from odoo.addons.mail.tests.test_mail_model import MailTest
MailTest._mail_flat_thread = False
fw_msg_id = '<THIS.IS.A.FW.MESSAGE.2@bert.fr>'
fw_message = MAIL_TEMPLATE.format(to='public@example.com',
cc='',
@@ -781,8 +786,11 @@ class TestMailgateway(TestMail):
self.env['mail.thread'].message_process(None, fw_message)
msg_fw = self.env['mail.message'].search([('message_id', '=', fw_msg_id)])
self.assertEqual(len(msg_fw), 1)
channel = self.env['mail.channel'].search([('name', "=", msg_fw.subject)])
channel = self.env['mail.test'].search([('name', "=", msg_fw.subject)])
self.assertEqual(len(channel), 0)
self.assertEqual(msg_fw.model, 'mail.channel')
self.assertEqual(msg_fw.model, 'mail.test')
self.assertFalse(msg_fw.parent_id)
self.assertTrue(msg_fw.res_id == self.group_public.id)
self.assertTrue(msg_fw.res_id == self.test_public.id)
# re-tmp
MailTest._mail_flat_thread = True
+49 -34
View File
@@ -10,21 +10,6 @@ from odoo.tools import mute_logger
class TestMailMessage(TestMail):
def setUp(self):
super(TestMailMessage, self).setUp()
self.group_private = self.env['mail.channel'].with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True
}).create({
'name': 'Private',
'public': 'private'}
).with_context({'mail_create_nosubscribe': False})
self.message = self.env['mail.message'].create({
'body': 'My Body',
'model': 'mail.channel',
'res_id': self.group_private.id,
})
def test_mail_message_values_basic(self):
self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink()
@@ -69,10 +54,10 @@ class TestMailMessage(TestMail):
self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink()
msg = self.env['mail.message'].sudo(self.user_employee).create({
'model': 'mail.channel',
'res_id': self.group_pigs.id
'model': 'mail.test',
'res_id': self.test_pigs.id
})
self.assertIn('-openerp-%d-mail.channel' % self.group_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertIn('-openerp-%d-mail.test' % self.test_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email))
self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email))
@@ -82,11 +67,11 @@ class TestMailMessage(TestMail):
self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink()
msg = self.env['mail.message'].sudo(self.user_employee).create({
'model': 'mail.channel',
'res_id': self.group_pigs.id
'model': 'mail.test',
'res_id': self.test_pigs.id
})
self.assertIn('-openerp-%d-mail.channel' % self.group_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertEqual(msg.reply_to, '%s %s <%s@%s>' % (self.env.user.company_id.name, self.group_pigs.name, self.group_pigs.alias_name, alias_domain))
self.assertIn('-openerp-%d-mail.test' % self.test_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertEqual(msg.reply_to, '%s %s <%s@%s>' % (self.env.user.company_id.name, self.test_pigs.name, self.test_pigs.alias_name, alias_domain))
self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email))
def test_mail_message_values_document_alias_catchall(self):
@@ -96,22 +81,22 @@ class TestMailMessage(TestMail):
self.env['ir.config_parameter'].set_param('mail.catchall.alias', alias_catchall)
msg = self.env['mail.message'].sudo(self.user_employee).create({
'model': 'mail.channel',
'res_id': self.group_pigs.id
'model': 'mail.test',
'res_id': self.test_pigs.id
})
self.assertIn('-openerp-%d-mail.channel' % self.group_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertEqual(msg.reply_to, '%s %s <%s@%s>' % (self.env.user.company_id.name, self.group_pigs.name, self.group_pigs.alias_name, alias_domain))
self.assertIn('-openerp-%d-mail.test' % self.test_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertEqual(msg.reply_to, '%s %s <%s@%s>' % (self.env.user.company_id.name, self.test_pigs.name, self.test_pigs.alias_name, alias_domain))
self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email))
def test_mail_message_values_no_auto_thread(self):
msg = self.env['mail.message'].sudo(self.user_employee).create({
'model': 'mail.channel',
'res_id': self.group_pigs.id,
'model': 'mail.test',
'res_id': self.test_pigs.id,
'no_auto_thread': True,
})
self.assertIn('reply_to', msg.message_id)
self.assertNotIn('mail.channel', msg.message_id)
self.assertNotIn('-%d-' % self.group_pigs.id, msg.message_id)
self.assertNotIn('mail.test', msg.message_id)
self.assertNotIn('-%d-' % self.test_pigs.id, msg.message_id)
def test_mail_message_notify_from_mail_mail(self):
# Due ot post-commit hooks, store send emails in every step
@@ -128,6 +113,36 @@ class TestMailMessage(TestMail):
self.assertNotIn(u'Ernest Employee <e.e@example.com>', self.email_to_list)
self.assertIn(u'test@example.com', self.email_to_list)
class TestMailMessageAccess(TestMail):
@classmethod
def setUpClass(cls):
super(TestMailMessageAccess, cls).setUpClass()
Channel = cls.env['mail.channel'].with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True
})
# Pigs: base group for tests
cls.group_pigs = Channel.create({
'name': 'Pigs',
'public': 'groups',
'group_public_id': cls.env.ref('base.group_user').id})
# Jobs: public group
cls.group_public = Channel.create({
'name': 'Jobs',
'description': 'NotFalse',
'public': 'public'})
# Private: private gtroup
cls.group_private = Channel.create({
'name': 'Private',
'public': 'private'})
cls.message = cls.env['mail.message'].create({
'body': 'My Body',
'model': 'mail.channel',
'res_id': cls.group_private.id,
})
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_mail_message_access_search(self):
# Data: various author_ids, partner_ids, documents
@@ -253,7 +268,7 @@ class TestMailMessage(TestMail):
self.env['mail.message'].sudo(self.user_employee).create({'model': 'mail.channel', 'res_id': self.group_private.id, 'body': 'Test', 'parent_id': self.message.id})
def test_message_set_star(self):
msg = self.group_pigs.message_post(body='My Body', subject='1')
msg = self.test_pigs.message_post(body='My Body', subject='1')
msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg.id)
# Admin set as starred
@@ -270,6 +285,6 @@ class TestMailMessage(TestMail):
self.assertTrue(msg_emp.starred)
def test_60_cache_invalidation(self):
msg_cnt = len(self.group_pigs.message_ids)
self.group_pigs.message_post(body='Hi!', subject='test')
self.assertEqual(len(self.group_pigs.message_ids), msg_cnt + 1)
msg_cnt = len(self.test_pigs.message_ids)
self.test_pigs.message_post(body='Hi!', subject='test')
self.assertEqual(len(self.test_pigs.message_ids), msg_cnt + 1)
+15 -2
View File
@@ -10,8 +10,21 @@ class MailTest(models.Model):
_description = 'Test Mail Model'
_name = 'mail.test'
_mail_post_access = 'read'
_inherit = ['mail.thread']
# _mail_flat_thread = False
_inherit = ['mail.thread', 'mail.alias.mixin']
name = fields.Char()
description = fields.Text()
alias_id = fields.Many2one(
'mail.alias', 'Alias')
'mail.alias', 'Alias',
delegate=True)
def get_alias_model_name(self, vals):
return vals.get('alias_model', 'mail.test')
def get_alias_values(self):
self.ensure_one()
res = super(MailTest, self).get_alias_values()
res['alias_force_thread_id'] = self.id
res['alias_parent_thread_id'] = self.id
return res
+31 -31
View File
@@ -32,7 +32,7 @@ class TestMailTemplate(TestMail):
self.email_2 = 'test2@example.com'
self.email_3 = self.partner_1.email
self.email_template = self.env['mail.template'].create({
'model_id': self.env['ir.model']._get('mail.channel').id,
'model_id': self.env['ir.model']._get('mail.test').id,
'name': 'Pigs Template',
'subject': '${object.name}',
'body_html': '${object.description}',
@@ -45,13 +45,13 @@ class TestMailTemplate(TestMail):
def test_composer_template_onchange(self):
composer = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'comment',
'default_model': 'mail.channel',
'default_res_id': self.group_pigs.id,
'default_model': 'mail.test',
'default_res_id': self.test_pigs.id,
'default_use_template': False,
'default_template_id': False
}).create({'subject': 'Forget me subject', 'body': 'Dummy body'})
values = composer.onchange_template_id(self.email_template.id, 'comment', 'mail.channel', self.group_pigs.id)['value']
values = composer.onchange_template_id(self.email_template.id, 'comment', 'mail.test', self.test_pigs.id)['value']
# use _convert_to_cache to return a browse record list from command list or id list for x2many fields
values = composer._convert_to_record(composer._convert_to_cache(values))
recipients = values['partner_ids']
@@ -59,8 +59,8 @@ class TestMailTemplate(TestMail):
test_recipients = self.env['res.partner'].search([('email', 'in', ['test1@example.com', 'test2@example.com'])]) | self.partner_1 | self.partner_2 | self.user_employee.partner_id
test_attachments = self.env['ir.attachment'].search([('name', 'in', ['_Test_First', '_Test_Second'])])
self.assertEqual(values['subject'], self.group_pigs.name)
self.assertEqual(values['body'], '<p>%s</p>' % self.group_pigs.description)
self.assertEqual(values['subject'], self.test_pigs.name)
self.assertEqual(values['body'], '<p>%s</p>' % self.test_pigs.description)
self.assertEqual(recipients, test_recipients)
self.assertEqual(set(recipients.mapped('email')), set([self.email_1, self.email_2, self.partner_1.email, self.partner_2.email, self.user_employee.email]))
self.assertEqual(attachments, test_attachments)
@@ -69,15 +69,15 @@ class TestMailTemplate(TestMail):
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_composer_template_send(self):
self.group_pigs.with_context(use_template=False).message_post_with_template(self.email_template.id, composition_mode='comment')
self.test_pigs.with_context(use_template=False).message_post_with_template(self.email_template.id, composition_mode='comment')
message = self.group_pigs.message_ids[0]
message = self.test_pigs.message_ids[0]
test_recipients = self.env['res.partner'].search([('email', 'in', ['test1@example.com', 'test2@example.com'])]) | self.partner_1 | self.partner_2 | self.user_employee.partner_id
self.assertEqual(message.subject, self.group_pigs.name)
self.assertEqual(message.body, '<p>%s</p>' % self.group_pigs.description)
self.assertEqual(message.subject, self.test_pigs.name)
self.assertEqual(message.body, '<p>%s</p>' % self.test_pigs.description)
self.assertEqual(message.partner_ids, test_recipients)
self.assertEqual(set(message.attachment_ids.mapped('res_model')), set(['mail.channel']))
self.assertEqual(set(message.attachment_ids.mapped('res_id')), set([self.group_pigs.id]))
self.assertEqual(set(message.attachment_ids.mapped('res_model')), set(['mail.test']))
self.assertEqual(set(message.attachment_ids.mapped('res_id')), set([self.test_pigs.id]))
# self.assertIn((attach.datas_fname, base64.b64decode(attach.datas)), _attachments_test,
# 'mail.message attachment name / data incorrect')
@@ -86,28 +86,28 @@ class TestMailTemplate(TestMail):
composer = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'mass_mail',
'default_notify': True,
'default_model': 'mail.channel',
'default_res_id': self.group_pigs.id,
'default_model': 'mail.test',
'default_res_id': self.test_pigs.id,
'default_template_id': self.email_template.id,
'active_ids': [self.group_pigs.id, self.group_public.id]
'active_ids': [self.test_pigs.id, self.test_public.id]
}).create({})
values = composer.onchange_template_id(self.email_template.id, 'mass_mail', 'mail.channel', self.group_pigs.id)['value']
values = composer.onchange_template_id(self.email_template.id, 'mass_mail', 'mail.test', self.test_pigs.id)['value']
composer.write(values)
composer.send_mail()
message_1 = self.group_pigs.message_ids[0]
message_2 = self.group_public.message_ids[0]
message_1 = self.test_pigs.message_ids[0]
message_2 = self.test_public.message_ids[0]
self.assertEqual(message_1.subject, self.group_pigs.name, 'mail.message subject on Pigs incorrect')
self.assertEqual(message_2.subject, self.group_public.name, 'mail.message subject on Bird incorrect')
self.assertIn(self.group_pigs.description, message_1.body, 'mail.message body on Pigs incorrect')
self.assertIn(self.group_public.description, message_2.body, 'mail.message body on Bird incorrect')
self.assertEqual(message_1.subject, self.test_pigs.name, 'mail.message subject on Pigs incorrect')
self.assertEqual(message_2.subject, self.test_public.name, 'mail.message subject on Bird incorrect')
self.assertIn(self.test_pigs.description, message_1.body, 'mail.message body on Pigs incorrect')
self.assertIn(self.test_public.description, message_2.body, 'mail.message body on Bird incorrect')
# todo for JDC: ! (False -> <p>False</p>)
def test_mail_template(self):
mail_id = self.email_template.send_mail(self.group_pigs.id)
mail_id = self.email_template.send_mail(self.test_pigs.id)
mail = self.env['mail.mail'].browse(mail_id)
self.assertEqual(mail.subject, self.group_pigs.name)
self.assertEqual(mail.subject, self.test_pigs.name)
self.assertEqual(mail.email_to, self.email_template.email_to)
self.assertEqual(mail.email_cc, self.email_template.email_cc)
self.assertEqual(mail.recipient_ids, self.partner_2 | self.user_employee.partner_id)
@@ -115,15 +115,15 @@ class TestMailTemplate(TestMail):
def test_message_compose_template_save(self):
self.env['mail.compose.message'].with_context(
{'default_composition_mode': 'comment',
'default_model': 'mail.channel',
'default_res_id': self.group_pigs.id,
'active_ids': [self.group_pigs.id, self.group_public.id]
'default_model': 'mail.test',
'default_res_id': self.test_pigs.id,
'active_ids': [self.test_pigs.id, self.test_public.id]
}).create({
'subject': 'Forget me subject',
'body': '<p>Dummy body</p>'
}).with_context({'default_model': 'mail.channel'}).save_as_template()
}).with_context({'default_model': 'mail.test'}).save_as_template()
# Test: email_template subject, body_html, model
last_template = self.env['mail.template'].search([('model', '=', 'mail.channel'), ('subject', '=', 'Forget me subject')], limit=1)
last_template = self.env['mail.template'].search([('model', '=', 'mail.test'), ('subject', '=', 'Forget me subject')], limit=1)
self.assertEqual(last_template.body_html, '<p>Dummy body</p>', 'email_template incorrect body_html')
def test_add_context_action(self):
@@ -143,8 +143,8 @@ class TestMailTemplate(TestMail):
self.email_template_in_2_days = self.email_template.copy()
self.email_template_in_2_days.write({'scheduled_date': "${(datetime.datetime.now() + relativedelta(days=2)).strftime('%Y-%m-%d %H:%M')}"})
mail_now_id = self.email_template.send_mail(self.group_pigs.id)
mail_in_2_days_id = self.email_template_in_2_days.send_mail(self.group_pigs.id)
mail_now_id = self.email_template.send_mail(self.test_pigs.id)
mail_in_2_days_id = self.email_template_in_2_days.send_mail(self.test_pigs.id)
mail_now = self.env['mail.mail'].browse(mail_now_id)
mail_in_2_days = self.env['mail.mail'].browse(mail_in_2_days_id)
+1 -1
View File
@@ -10,7 +10,7 @@ class TestMessageRead(TestMail):
@mute_logger('odoo.addons.mail.models.mail_mail')
def setUp(self):
super(TestMessageRead, self).setUp()
self.user_employee.write({'notify_email': 'none'})
self.user_employee.write({'notification_type': 'inbox'})
self.group_pigs.message_subscribe_users([self.user_employee.id])
self.msg_0 = self.group_pigs.message_post(body='0', subtype='mt_comment')
self.msg_1 = self.group_pigs.message_post(body='1', subtype='mt_comment')
+17 -13
View File
@@ -9,13 +9,17 @@ class TestTracking(TestMail):
def test_message_track(self):
""" Testing auto tracking of fields. Warning, it has not be cleaned and
should probably be. """
test_channel = self.env['mail.channel'].create({
'name': 'Test',
'channel_partner_ids': [(4, self.user_employee.partner_id.id)]
})
Subtype = self.env['mail.message.subtype']
Data = self.env['ir.model.data']
note_subtype = self.env.ref('mail.mt_note')
group_system = self.env.ref('base.group_system')
group_user = self.env.ref('base.group_user')
self.group_pigs.write({'channel_partner_ids': [(4, self.user_employee.partner_id.id)]})
# mt_private: public field (tracked as onchange) set to 'private' (selection)
mt_private = Subtype.create({
@@ -94,21 +98,21 @@ class TestTracking(TestMail):
del getattr(cls, key).track_visibility
# Test: change name -> always tracked, not related to a subtype
self.group_pigs.sudo(self.user_employee).write({'name': 'my_name'})
self.assertEqual(len(self.group_pigs.message_ids), 1)
last_msg = self.group_pigs.message_ids[-1]
test_channel.sudo(self.user_employee).write({'name': 'my_name'})
self.assertEqual(len(test_channel.message_ids), 1)
last_msg = test_channel.message_ids[-1]
self.assertEqual(last_msg.subtype_id, note_subtype)
self.assertEqual(len(last_msg.tracking_value_ids), 1)
self.assertEqual(last_msg.tracking_value_ids.field, 'name')
self.assertEqual(last_msg.tracking_value_ids.field_desc, 'Name')
self.assertEqual(last_msg.tracking_value_ids.old_value_char, 'Pigs')
self.assertEqual(last_msg.tracking_value_ids.old_value_char, 'Test')
self.assertEqual(last_msg.tracking_value_ids.new_value_char, 'my_name')
# Test: change name as supername, public as private -> 1 subtype, private
self.group_pigs.sudo(self.user_employee).write({'name': 'supername', 'public': 'private'})
self.group_pigs.invalidate_cache()
self.assertEqual(len(self.group_pigs.message_ids.ids), 2)
last_msg = self.group_pigs.message_ids[0]
test_channel.sudo(self.user_employee).write({'name': 'supername', 'public': 'private'})
test_channel.invalidate_cache()
self.assertEqual(len(test_channel.message_ids.ids), 2)
last_msg = test_channel.message_ids[0]
self.assertEqual(last_msg.subtype_id, mt_private)
self.assertEqual(len(last_msg.tracking_value_ids), 2)
self.assertEqual(set(last_msg.tracking_value_ids.mapped('field')), set(['name', 'public']))
@@ -117,10 +121,10 @@ class TestTracking(TestMail):
self.assertEqual(set(last_msg.tracking_value_ids.mapped('new_value_char')), set(['supername', 'Invited people only']))
# Test: change public as public, group_public_id -> 1 subtype, group public set
self.group_pigs.sudo(self.user_employee).write({'public': 'public', 'group_public_id': group_system.id})
self.group_pigs.invalidate_cache()
self.assertEqual(len(self.group_pigs.message_ids), 3)
last_msg = self.group_pigs.message_ids[0]
test_channel.sudo(self.user_employee).write({'public': 'public', 'group_public_id': group_system.id})
test_channel.invalidate_cache()
self.assertEqual(len(test_channel.message_ids), 3)
last_msg = test_channel.message_ids[0]
self.assertEqual(last_msg.subtype_id, mt_group_public_set)
self.assertEqual(len(last_msg.tracking_value_ids), 3)
self.assertEqual(set(last_msg.tracking_value_ids.mapped('field')), set(['group_public_id', 'public', 'name']))
-1
View File
@@ -8,7 +8,6 @@
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='user_id']" position="after">
<field name='notify_email' widget="radio" groups="base.group_no_one"/>
<field name="opt_out" string="Mailing Opt-Out" groups="base.group_no_one"/>
<field name="message_bounce" groups="base.group_no_one"/>
</xpath>
+2 -2
View File
@@ -10,7 +10,7 @@
<field name="arch" type="xml">
<data>
<field name="email" position="before">
<field name="notify_email" widget="radio" readonly="0"/>
<field name="notification_type" widget="radio" readonly="0"/>
</field>
</data>
</field>
@@ -24,7 +24,7 @@
<field name="arch" type="xml">
<data>
<field name="signature" position="before">
<field name="notify_email" widget="radio"/>
<field name="notification_type" widget="radio"/>
</field>
<field name="signature" position="before">
<field name="alias_id"/>
+2 -2
View File
@@ -24,13 +24,13 @@ class TestMrpCommon(common2.TestStockCommon):
'name': 'Hilda Ferachwal',
'login': 'hilda',
'email': 'h.h@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [user_group_mrp_user.id])]})
cls.user_mrp_manager = Users.create({
'name': 'Gary Youngwomen',
'login': 'gary',
'email': 'g.g@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [user_group_mrp_manager.id])]})
cls.workcenter_1 = cls.env['mrp.workcenter'].create({
+1 -1
View File
@@ -8,7 +8,6 @@
<field name="email">demo.portal@yourcompany.example.com</field>
<field name="supplier" eval="False"/>
<field name="customer" eval="True"/>
<field name="notify_email">none</field>
<field name="city">Vivegnis</field>
<field name="zip">4683</field>
<field name="country_id" ref="base.be"/>
@@ -19,6 +18,7 @@
<field name="partner_id" ref="partner_demo_portal"/>
<field name="login">portal</field>
<field name="password">portal</field>
<field name="notification_type">inbox</field>
<field name="signature"><![CDATA[<span>-- <br/>
Mr Demo Portal</span>]]></field>
<!-- Avoid auto-including this user in any default group -->
+14 -10
View File
@@ -8,16 +8,19 @@ from odoo.tools.misc import mute_logger
class TestPortal(TestMail):
def test_mail_compose_access_rights(self):
self.group_pigs.write({'group_public_id': self.env.ref('base.group_portal').id})
port_msg = self.group_pigs.message_post(body='Message')
test_channel = self.env['mail.channel'].create({
'name': 'Pigs',
'public': 'groups',
'group_public_id': self.env.ref('base.group_portal').id})
port_msg = test_channel.message_post(body='Message')
# Do: Chell comments Pigs, ok because can write on it (public group)
self.group_pigs.sudo(self.user_portal).message_post(body='I love Pigs', message_type='comment', subtype='mail.mt_comment')
test_channel.sudo(self.user_portal).message_post(body='I love Pigs', message_type='comment', subtype='mail.mt_comment')
# Do: Chell creates a mail.compose.message record on Pigs, because he uses the wizard
compose = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'comment',
'default_model': 'mail.channel',
'default_res_id': self.group_pigs.id
'default_res_id': test_channel.id
}).sudo(self.user_portal).create({
'subject': 'Subject',
'body': 'Body text',
@@ -35,7 +38,8 @@ class TestPortal(TestMail):
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_invite_email_portal(self):
group_pigs = self.group_pigs
test_record = self.env['mail.test'].create({'name': 'Pigs'})
base_url = self.env['ir.config_parameter'].get_param('web.base.url', default='')
# Carine Poilvache, with email, should receive emails for comments and emails
partner_carine = self.env['res.partner'].create({'name': 'Carine Poilvache', 'email': 'c@c'})
@@ -43,12 +47,12 @@ class TestPortal(TestMail):
# Do: create a mail_wizard_invite, validate it
self._init_mock_build_email()
mail_invite = self.env['mail.wizard.invite'].with_context({
'default_res_model': 'mail.channel',
'default_res_id': group_pigs.id}).create({
'default_res_model': 'mail.test',
'default_res_id': test_record.id}).create({
'partner_ids': [(4, partner_carine.id)], 'send_mail': True})
mail_invite.add_followers()
# Test: Pigs followers should contain Admin and Bert
self.assertEqual(group_pigs.message_partner_ids, partner_carine)
self.assertIn(partner_carine, test_record.message_partner_ids)
# Test: partner must have been prepared for signup
# TDE FIXME: invite email for portal users should be fixed / improved / rethought
# self.assertTrue(partner_carine.signup_valid, 'partner has not been prepared for signup')
@@ -59,10 +63,10 @@ class TestPortal(TestMail):
self.assertEqual(len(self._mails), 1, 'sent email number incorrect, should be only for Bert')
for sent_email in self._mails:
self.assertEqual(
sent_email.get('subject'), 'Invitation to follow Discussion channel: Pigs',
sent_email.get('subject'), 'Invitation to follow %s: Pigs' % self.env['mail.test']._description,
'invite: subject of invitation email is incorrect')
self.assertIn(
'Administrator invited you to follow Discussion channel document: Pigs', sent_email.get('body'),
'Administrator invited you to follow %s document: Pigs' % self.env['mail.test']._description, sent_email.get('body'),
'invite: body of invitation email is incorrect')
# self.assertIn(
# partner_carine.signup_token, sent_email.get('body'),
+1 -1
View File
@@ -23,5 +23,5 @@ class TestStockCommon(common.TestProductCommon):
'name': 'Fabricette Manivelle',
'login': 'fabricette',
'email': 'f.f@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [user_group_employee.id])]})
+19
View File
@@ -264,6 +264,25 @@ class Project(models.Model):
self.with_context(active_test=False).mapped('tasks').write({'active': vals['active']})
return res
@api.multi
def message_subscribe(self, partner_ids=None, channel_ids=None, subtype_ids=None, force=True):
""" Subscribe to all existing active tasks when subscribing to a project """
res = super(Project, self).message_subscribe(partner_ids=partner_ids, channel_ids=channel_ids, subtype_ids=subtype_ids, force=force)
if not subtype_ids or any(subtype.parent_id.model == 'project.task' for subtype in self.env['mail.message.subtype'].browse(subtype_ids)):
for partner_id in partner_ids or []:
self.mapped('tasks').filtered(lambda task: not task.stage_id.fold and partner_id not in task.message_partner_ids.ids).message_subscribe(
partner_ids=[partner_id], channel_ids=None, subtype_ids=None, force=False)
for channel_id in channel_ids or []:
self.mapped('tasks').filtered(lambda task: not task.stage_id.fold and channel_id not in task.message_channel_ids.ids).message_subscribe(
partner_ids=None, channel_ids=[channel_id], subtype_ids=None, force=False)
return res
@api.multi
def message_unsubscribe(self, partner_ids=None, channel_ids=None):
""" Unsubscribe from all tasks when unsubscribing from a project """
self.mapped('tasks').message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids)
return super(Project, self).message_unsubscribe(partner_ids=partner_ids, channel_ids=channel_ids)
@api.multi
def toggle_favorite(self):
favorite_projects = not_fav_projects = self.env['project.project'].sudo()
+1 -1
View File
@@ -15,7 +15,7 @@ class TestPortalProjectBase(TestProjectBase):
'login': 'noemie',
'email': 'n.n@example.com',
'signature': '--\nNoemie',
'notify_email': 'always',
'notification_type': 'email',
'groups_id': [(6, 0, [])]})
self.task_3 = self.env['project.task'].with_context({'mail_create_nolog': True}).create({
+1 -1
View File
@@ -20,7 +20,7 @@ class TestCreatePicking(common.TestProductCommon):
'name': 'Pauline Poivraisselle',
'login': 'pauline',
'email': 'pur@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [res_users_purchase_user.id])]})
self.po_vals = {
+2 -2
View File
@@ -15,7 +15,7 @@ class TestSale(AccountingTestCase):
'login': 'manager',
'email': 'a.m@example.com',
'signature': '--\nAndreww',
'notify_email': 'always',
'notification_type': 'email',
'groups_id': [(6, 0, [group_manager.id])]
})
self.user = self.env['res.users'].create({
@@ -23,7 +23,7 @@ class TestSale(AccountingTestCase):
'login': 'user',
'email': 'm.u@example.com',
'signature': '--\nMark',
'notify_email': 'always',
'notification_type': 'email',
'groups_id': [(6, 0, [group_user.id])]
})
# create quotation with differend kinds of products (all possible combinations)
+2 -2
View File
@@ -59,13 +59,13 @@ class TestStockCommon(common.TestProductCommon):
'name': 'Pauline Poivraisselle',
'login': 'pauline',
'email': 'p.p@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [user_group_stock_user.id])]})
cls.user_stock_manager = Users.create({
'name': 'Julie Tablier',
'login': 'julie',
'email': 'j.j@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [user_group_stock_manager.id])]})
# Warehouses
+3 -3
View File
@@ -18,20 +18,20 @@ class TestWebsiteBlogCommon(common.TransactionCase):
'name': 'Armande Employee',
'login': 'armande',
'email': 'armande.employee@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [group_employee_id])]
})
self.user_blogmanager = Users.with_context({'no_reset_password': True}).create({
'name': 'Bastien BlogManager',
'login': 'bastien',
'email': 'bastien.blogmanager@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [group_blog_manager_id, group_employee_id])]
})
self.user_public = Users.with_context({'no_reset_password': True}).create({
'name': 'Cedric Public',
'login': 'cedric',
'email': 'cedric.public@example.com',
'notify_email': 'none',
'notification_type': 'inbox',
'groups_id': [(6, 0, [group_public_id])]
})
@@ -238,16 +238,4 @@ Our ERP expertise is since 2005 and we mainly focus on Odoo Implementation acros
Best Designers has now emerged serving the Small and Medium Business – SMB’s with lots of Free and Open Source Software's, Our team is proficient to deliver quick and quality solutions. With a blend of experts with proven track record, our enterprise solution Business Consultants, ERP Consultants, Network Engineers, Software Developers, Web Architects, Software Testers and Search Engine Optimizers makes it possible to offer our clients affordable solutions that are both innovative and highly influential.
]]></field>
</record>
<record id="base.res_partner_10" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_2" model="res.partner">
<field name="notify_email">none</field>
</record>
<record id="base.res_partner_1" model="res.partner">
<field name="notify_email">none</field>
</record>
</odoo>