[REF] mail: migrated tests to the new API and refactored them.

Tests have been migrated to the new api to prepare the migration of the
mail module itself. Moreover tests have been cleaned: redundant tests
and unnecessary tests have been removed.

As the base test class in mail is used in other addons, other addons
have been updated :
- portal
- project
- portal_project
- website_project_issue
- sale
- purchase

Future commits will come with somes fixes for issues detected when cleaning
the tests.
This commit is contained in:
Jignesh Rathod
2015-03-24 10:18:16 +01:00
committed by Thibault Delavallée
parent 573341c906
commit b55969a577
22 changed files with 1795 additions and 2996 deletions
+10 -20
View File
@@ -1,22 +1,12 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_mail_group, test_mail_message, test_mail_features, test_mail_gateway, test_message_read, test_invite, test_mail, test_ir_actions
import test_mail_followers
import test_mail_message
import test_mail_features
import test_mail_group
import test_mail_gateway
import test_message_read
import test_message_track
import test_mail_template
import test_invite
import test_ir_actions
+127 -90
View File
@@ -1,23 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import socket
from openerp.tests import common
@@ -25,108 +8,162 @@ from openerp.tests import common
class TestMail(common.TransactionCase):
def _init_mock_build_email(self):
self._build_email_args_list = []
self._build_email_kwargs_list = []
self._mails_args = []
self._mails = []
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.group', 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'].message_process(model, mail)
return self.env[target_model].search([(target_field, '=', subject)])
def setUp(self):
super(TestMail, self).setUp()
cr, uid = self.cr, self.uid
# Install mock SMTP gateway
test = self
Test = self
def build_email(self, *args, **kwargs):
test._build_email_args_list.append(args)
test._build_email_kwargs_list.append(kwargs)
Test._mails_args.append(args)
Test._mails.append(kwargs)
return build_email.origin(self, *args, **kwargs)
def send_email(self, cr, uid, message, *args, **kwargs):
return message['Message-Id']
self._init_mock_build_email()
self.registry('ir.mail_server')._patch_method('build_email', build_email)
self.registry('ir.mail_server')._patch_method('send_email', send_email)
self.env['ir.mail_server']._patch_method('build_email', build_email)
self.env['ir.mail_server']._patch_method('send_email', send_email)
# Usefull models
self.ir_model = self.registry('ir.model')
self.ir_model_data = self.registry('ir.model.data')
self.ir_attachment = self.registry('ir.attachment')
self.mail_alias = self.registry('mail.alias')
self.mail_thread = self.registry('mail.thread')
self.mail_group = self.registry('mail.group')
self.mail_mail = self.registry('mail.mail')
self.mail_message = self.registry('mail.message')
self.mail_notification = self.registry('mail.notification')
self.mail_followers = self.registry('mail.followers')
self.mail_message_subtype = self.registry('mail.message.subtype')
self.res_users = self.registry('res.users')
self.res_partner = self.registry('res.partner')
# Find Employee group
group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user')
self.group_employee_id = group_employee_ref and group_employee_ref[1] or False
# Partner Data
# User groups
user_group_employee = self.env.ref('base.group_user')
user_group_portal = self.env.ref('base.group_portal')
user_group_public = self.env.ref('base.group_public')
# User Data: employee, noone
self.user_employee_id = self.res_users.create(cr, uid, {
Users = self.env['res.users'].with_context({'no_reset_password': True})
self.user_employee = Users.create({
'name': 'Ernest Employee',
'login': 'ernest',
'alias_name': 'ernest',
'email': 'e.e@example.com',
'signature': '--\nErnest',
'notify_email': 'always',
'groups_id': [(6, 0, [self.group_employee_id])]
}, {'no_reset_password': True})
self.user_noone_id = self.res_users.create(cr, uid, {
'groups_id': [(6, 0, [user_group_employee.id])]})
self.user_employee_2 = Users.create({
'name': 'Raoul Grosbedon',
'login': 'raoul',
'alias_name': 'raoul',
'email': 'r.g@example.com',
'signature': 'SignRaoul',
'notify_email': 'always',
'groups_id': [(6, 0, [user_group_employee.id])]})
self.user_noone = Users.create({
'name': 'Noemie NoOne',
'login': 'noemie',
'alias_name': 'noemie',
'email': 'n.n@example.com',
'signature': '--\nNoemie',
'notify_email': 'always',
'groups_id': [(6, 0, [])]
}, {'no_reset_password': True})
# Test users to use through the various tests
self.res_users.write(cr, uid, [uid], {'name': 'Administrator'})
self.user_raoul_id = self.res_users.create(cr, uid, {
'name': 'Raoul Grosbedon',
'signature': 'SignRaoul',
'email': 'raoul@raoul.fr',
'login': 'raoul',
'alias_name': 'raoul',
'groups_id': [(6, 0, [self.group_employee_id])]
})
self.user_bert_id = self.res_users.create(cr, uid, {
'groups_id': [(6, 0, [])]})
self.user_public = Users.create({
'name': 'Bert Tartignole',
'signature': 'SignBert',
'email': 'bert@bert.fr',
'login': 'bert',
'alias_name': 'bert',
'groups_id': [(6, 0, [])]
'email': 'b.t@example.com',
'signature': 'SignBert',
'notify_email': 'always',
'groups_id': [(6, 0, [user_group_public.id])]})
self.user_portal = Users.create({
'name': 'Chell Gladys',
'login': 'chell',
'alias_name': 'chell',
'email': 'chell@gladys.portal',
'signature': 'SignChell',
'notify_email': 'always',
'groups_id': [(6, 0, [user_group_portal.id])]})
self.user_admin = self.env.user
# Update admin
# Set an email address for the user running the tests, used as Sender for outgoing mails
self._company_name = 'TestCompany'
self._admin_name = 'Administrator'
self._admin_email = 'test@localhost'
self.user_admin.write({
'email': self._admin_email,
'name': self._admin_name,
'signature': 'SignAdmin',
'notify_email': 'always',
})
self.user_admin.company_id.write({
'name': self._company_name,
})
self.user_raoul = self.res_users.browse(cr, uid, self.user_raoul_id)
self.user_bert = self.res_users.browse(cr, uid, self.user_bert_id)
self.user_admin = self.res_users.browse(cr, uid, uid)
self.partner_admin_id = self.user_admin.partner_id.id
self.partner_raoul_id = self.user_raoul.partner_id.id
self.partner_bert_id = self.user_bert.partner_id.id
# Test 'pigs' group to use through the various tests
self.group_pigs_id = self.mail_group.create(
cr, uid,
{'name': 'Pigs', 'description': 'Fans of Pigs, unite !', 'alias_name': 'group+pigs'},
{'mail_create_nolog': True}
)
self.group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
# Test mail.group: public to provide access to everyone
self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'})
# Test mail.group: private to restrict access
self.group_priv_id = self.mail_group.create(cr, uid, {'name': 'Private', 'public': 'private'})
# Test Data for Partners
self.partner_1 = self.env['res.partner'].create({
'name': 'Valid Lelitre',
'email': 'valid.lelitre@agrolait.com',
'notify_email': 'always'})
self.partner_2 = self.env['res.partner'].create({
'name': 'Valid Poilvache',
'email': 'valid.other@gmail.com',
'notify_email': 'always'})
# Create test groups without followers and messages by default
TestMailGroup = self.env['mail.group'].with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True
})
# Pigs: base group for tests
self.group_pigs = TestMailGroup.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
self.group_public = TestMailGroup.create({
'name': 'Jobs',
'description': 'NotFalse',
'public': 'public',
'alias_name': 'public',
'alias_contact': 'everyone'}
).with_context({'mail_create_nosubscribe': False})
# Private: private group
self.group_private = TestMailGroup.create({
'name': 'Private',
'public': 'private'}
).with_context({'mail_create_nosubscribe': False})
# Portal: group-based group using portal group
self.group_portal = TestMailGroup.create({
'name': 'PigsPortal',
'public': 'groups',
'group_public_id': user_group_portal.id}
).with_context({'mail_create_nosubscribe': False})
# groups@.. will cause the creation of new mail groups
self.mail_group_model = self.env['ir.model'].search([('model', '=', 'mail.group')], limit=1)
self.alias = self.env['mail.alias'].create({
'alias_name': 'groups',
'alias_user_id': False,
'alias_model_id': self.mail_group_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.group',
'res_id': self.group_public.id,
'subject': 'Public Discussion',
'type': 'email',
'author_id': self.partner_1.id,
'message_id': '<123456-openerp-%s-mail.group@%s>' % (self.group_public.id, socket.gethostname()),
})
self._init_mock_build_email()
def tearDown(self):
# Remove mocks
self.registry('ir.mail_server')._revert_method('build_email')
self.registry('ir.mail_server')._revert_method('send_email')
self.env['ir.mail_server']._revert_method('build_email')
self.env['ir.mail_server']._revert_method('send_email')
super(TestMail, self).tearDown()
+25 -38
View File
@@ -1,48 +1,35 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.mail.tests.common import TestMail
from openerp.tools import mute_logger
class test_invite(TestMail):
class TestInvite(TestMail):
def test_00_basic_invite(self):
cr, uid = self.cr, self.uid
mail_invite = self.registry('mail.wizard.invite')
# Do: create a mail_wizard_invite, validate it
self._init_mock_build_email()
context = {'default_res_model': 'mail.group', 'default_res_id': self.group_pigs_id}
mail_invite_id = mail_invite.create(cr, self.user_raoul_id, {'partner_ids': [(4, self.partner_bert_id)], 'send_mail': True}, context)
mail_invite.add_followers(cr, self.user_raoul_id, [mail_invite_id], {'default_model': 'mail.group', 'default_res_id': 0})
@mute_logger('openerp.addons.mail.mail_mail')
def test_invite_email(self):
mail_invite = self.env['mail.wizard.invite'].with_context({
'default_res_model': 'mail.group',
'default_res_id': self.group_pigs.id
}).sudo(self.user_employee.id).create({
'partner_ids': [(4, self.user_portal.partner_id.id), (4, self.user_employee_2.partner_id.id)],
'send_mail': True})
mail_invite.add_followers()
# Test: Pigs followers should contain Admin, Bert
self.group_pigs.refresh()
follower_ids = [follower.id for follower in self.group_pigs.message_follower_ids]
self.assertEqual(set(follower_ids), set([self.partner_admin_id, self.partner_bert_id]), 'invite: Pigs followers after invite is incorrect')
self.assertEqual(self.group_pigs.message_follower_ids,
self.user_portal.partner_id | self.user_employee_2.partner_id,
'invite wizard: Pigs followers after invite is incorrect, should be Admin + added follower')
# Test: (pretend to) send email and check subject, body
self.assertEqual(len(self._build_email_kwargs_list), 1, 'sent email number incorrect, should be only for Bert')
for sent_email in self._build_email_kwargs_list:
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Discussion group: Pigs',
'invite: subject of invitation email is incorrect')
self.assertIn('Raoul Grosbedon invited you to follow Discussion group document: Pigs', sent_email.get('body'),
'invite: body of invitation email is incorrect')
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 group: Pigs',
'invite wizard: subject of invitation email is incorrect')
self.assertEqual(self._mails[1].get('subject'), 'Invitation to follow Discussion group: Pigs',
'invite wizard: subject of invitation email is incorrect')
self.assertIn('%s invited you to follow Discussion group document: Pigs' % self.user_employee.name,
self._mails[0].get('body'),
'invite wizard: body of invitation email is incorrect')
self.assertIn('%s invited you to follow Discussion group document: Pigs' % self.user_employee.name,
self._mails[1].get('body'),
'invite wizard: body of invitation email is incorrect')
+6 -32
View File
@@ -1,23 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.base.tests.test_ir_actions import TestServerActionsBase
@@ -26,10 +7,8 @@ class TestServerActionsEmail(TestServerActionsBase):
def test_00_state_email(self):
""" Test ir.actions.server email type """
cr, uid = self.cr, self.uid
# create email_template
template_id = self.registry('mail.template').create(cr, uid, {
email_template = self.env['mail.template'].create({
'name': 'TestTemplate',
'email_from': 'myself@example.com',
'email_to': 'brigitte@example.com',
@@ -38,18 +17,13 @@ class TestServerActionsEmail(TestServerActionsBase):
'subject': 'About ${object.name}',
'body_html': '<p>Dear ${object.name}, your parent is ${object.parent_id and object.parent_id.name or "False"}</p>',
})
self.ir_actions_server.write(cr, uid, self.act_id, {
'state': 'email',
'template_id': template_id,
})
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
action = self.env['ir.actions.server'].browse(self.act_id)
action.write({'state': 'email', 'template_id': email_template.id})
run_res = action.with_context(self.context).run()
self.assertFalse(run_res, 'ir_actions_server: email server action correctly finished should return False')
# check an email is waiting for sending
mail_ids = self.registry('mail.mail').search(cr, uid, [('subject', '=', 'About TestingPartner')])
self.assertEqual(len(mail_ids), 1, 'ir_actions_server: TODO')
mail = self.env['mail.mail'].search([('subject', '=', 'About TestingPartner')])
self.assertEqual(len(mail.ids), 1, 'ir_actions_server: TODO')
# check email content
mail = self.registry('mail.mail').browse(cr, uid, mail_ids[0])
self.assertEqual(mail.body, '<p>Dear TestingPartner, your parent is False</p>',
'ir_actions_server: TODO')
-244
View File
@@ -1,244 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import base64
from openerp.addons.mail.tests.common import TestMail
from openerp.tools import mute_logger
class test_message_compose(TestMail):
def setUp(self):
super(test_message_compose, self).setUp()
# create a 'pigs' and 'bird' groups that will be used through the various tests
self.group_bird_id = self.mail_group.create(self.cr, self.uid,
{'name': 'Bird', 'description': 'I am angry !'})
def test_00_message_compose_wizard(self):
""" Tests designed for the mail.compose.message wizard updated by email_template. """
cr, uid = self.cr, self.uid
mail_compose = self.registry('mail.compose.message')
self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a.a'})
user_admin = self.res_users.browse(cr, uid, uid)
p_a_id = user_admin.partner_id.id
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
group_bird = self.mail_group.browse(cr, uid, self.group_bird_id)
# Mail data
_subject1 = 'Pigs'
_subject2 = 'Bird'
_body_html1 = 'Fans of Pigs, unite !'
_body_html2 = 'I am angry !'
_attachments = [
{'name': 'First', 'datas_fname': 'first.txt', 'datas': base64.b64encode('My first attachment'), 'res_model': 'res.partner', 'res_id': self.partner_admin_id},
{'name': 'Second', 'datas_fname': 'second.txt', 'datas': base64.b64encode('My second attachment'), 'res_model': 'res.partner', 'res_id': self.partner_admin_id},
]
_attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')]
# Create template on mail.group, with attachments
group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0]
email_template = self.registry('mail.template')
email_template_id = email_template.create(cr, uid, {
'model_id': group_model_id,
'name': 'Pigs Template',
'subject': '${object.name}',
'body_html': '${object.description}',
'user_signature': False,
'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])],
'email_to': 'b@b.b, c@c.c',
'email_cc': 'd@d.d'
})
# ----------------------------------------
# CASE1: comment and save as template
# ----------------------------------------
# 1. Comment on pigs
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': '<p>Dummy body</p>'},
{'default_composition_mode': 'comment',
'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
# 2. Save current composition form as a template
mail_compose.save_as_template(cr, uid, [compose_id], context={'default_model': 'mail.group'})
# Test: email_template subject, body_html, model
last_template_id = email_template.search(cr, uid, [('model', '=', 'mail.group'), ('subject', '=', 'Forget me subject')], limit=1)[0]
self.assertTrue(last_template_id, 'email_template not found for model mail.group, subject Forget me subject')
last_template = email_template.browse(cr, uid, last_template_id)
self.assertEqual(last_template.body_html, '<p>Dummy body</p>', 'email_template incorrect body_html')
# ----------------------------------------
# CASE2: comment with template, save as template
# ----------------------------------------
# 1. Comment on pigs
context = {
'default_composition_mode': 'comment',
'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
'default_use_template': False,
'default_template_id': email_template_id,
'active_ids': [self.group_pigs_id, self.group_bird_id]
}
compose_id = mail_compose.create(cr, uid, {'subject': 'Forget me subject', 'body': 'Dummy body'}, context)
compose = mail_compose.browse(cr, uid, compose_id, context)
onchange_res = compose.onchange_template_id(email_template_id, 'comment', 'mail.group', self.group_pigs_id)['value']
onchange_res['partner_ids'] = [(4, partner_id) for partner_id in onchange_res.pop('partner_ids', [])]
onchange_res['attachment_ids'] = [(4, attachment_id) for attachment_id in onchange_res.pop('attachment_ids', [])]
compose.write(onchange_res)
compose.refresh()
message_pids = [partner.id for partner in compose.partner_ids]
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])])
# Test: mail.compose.message: subject, body, partner_ids
self.assertEqual(compose.subject, _subject1, 'mail.compose.message subject incorrect')
self.assertIn(_body_html1, compose.body, 'mail.compose.message body incorrect')
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# Test: mail.compose.message: attachments (owner has not been modified)
for attach in compose.attachment_ids:
self.assertEqual(attach.res_model, 'res.partner', 'mail.compose.message attachment res_model through templat was overriden')
self.assertEqual(attach.res_id, self.partner_admin_id, 'mail.compose.message attachment res_id incorrect')
self.assertIn((attach.datas_fname, base64.b64decode(attach.datas)), _attachments_test,
'mail.message attachment name / data incorrect')
# Test: mail.message: attachments
mail_compose.send_mail(cr, uid, [compose_id])
group_pigs.refresh()
message_pigs = group_pigs.message_ids[0]
for attach in message_pigs.attachment_ids:
self.assertEqual(attach.res_model, 'mail.group', 'mail.compose.message attachment res_model through templat was overriden')
self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.compose.message attachment res_id incorrect')
self.assertIn((attach.datas_fname, base64.b64decode(attach.datas)), _attachments_test,
'mail.message attachment name / data incorrect')
# ----------------------------------------
# CASE3: mass_mail with template
# ----------------------------------------
# 1. Mass_mail on pigs and bird, with a default_partner_ids set to check he is correctly added
context = {
'default_composition_mode': 'mass_mail',
'default_notify': True,
'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
'default_template_id': email_template_id,
'default_partner_ids': [p_a_id],
'active_ids': [self.group_pigs_id, self.group_bird_id]
}
compose_id = mail_compose.create(cr, uid, {'subject': 'Forget me subject', 'body': 'Dummy body'}, context)
compose = mail_compose.browse(cr, uid, compose_id, context)
onchange_res = compose.onchange_template_id(email_template_id, 'mass_mail', 'mail.group', self.group_pigs_id)['value']
onchange_res['partner_ids'] = [(4, partner_id) for partner_id in onchange_res.pop('partner_ids', [])]
onchange_res['attachment_ids'] = [(4, attachment_id) for attachment_id in onchange_res.pop('attachment_ids', [])]
compose.write(onchange_res)
compose.refresh()
message_pids = [partner.id for partner in compose.partner_ids]
partner_ids = [p_a_id]
self.assertEqual(compose.subject, '${object.name}', 'mail.compose.message subject incorrect')
self.assertEqual(compose.body, '<p>${object.description}</p>', 'mail.compose.message body incorrect') # todo: check signature
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# 2. Post the comment, get created message
mail_compose.send_mail(cr, uid, [compose_id], context={'default_res_id': -1, 'active_ids': [self.group_pigs_id, self.group_bird_id]})
group_pigs.refresh()
group_bird.refresh()
message_pigs = group_pigs.message_ids[0]
message_bird = group_bird.message_ids[0]
# Test: subject, body
self.assertEqual(message_pigs.subject, _subject1, 'mail.message subject on Pigs incorrect')
self.assertEqual(message_bird.subject, _subject2, 'mail.message subject on Bird incorrect')
self.assertIn(_body_html1, message_pigs.body, 'mail.message body on Pigs incorrect')
self.assertIn(_body_html2, message_bird.body, 'mail.message body on Bird incorrect')
# Test: partner_ids: p_a_id (default) + 3 newly created partners
# message_pigs_pids = [partner.id for partner in message_pigs.notified_partner_ids]
# message_bird_pids = [partner.id for partner in message_bird.notified_partner_ids]
# partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])])
# partner_ids.append(p_a_id)
# self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of notified_partner_ids')
# self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird notified_partner_ids incorrect')
# ----------------------------------------
# CASE4: test newly introduced partner_to field
# ----------------------------------------
# get already-created partners back
p_b_id = self.res_partner.search(cr, uid, [('email', '=', 'b@b.b')])[0]
p_c_id = self.res_partner.search(cr, uid, [('email', '=', 'c@c.c')])[0]
p_d_id = self.res_partner.search(cr, uid, [('email', '=', 'd@d.d')])[0]
# modify template: use partner_to, use template and email address in email_to to test all features together
user_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'res.users')])[0]
email_template.write(cr, uid, [email_template_id], {
'model_id': user_model_id,
'body_html': '${object.login}',
'email_to': '${object.email}, c@c',
'partner_to': '%i,%i' % (p_b_id, p_c_id),
'email_cc': 'd@d',
})
# patner by email + partner by id (no double)
send_to = [p_a_id, p_b_id, p_c_id, p_d_id]
# Generate messsage with default email and partner on template
mail_value = mail_compose.generate_email_for_composer(cr, uid, email_template_id, uid)
self.assertEqual(set(mail_value['partner_ids']), set(send_to), 'mail.message partner_ids list created by template is incorrect')
@mute_logger('openerp.models')
def test_10_email_templating(self):
""" Tests designed for the mail.compose.message wizard updated by email_template. """
cr, uid, context = self.cr, self.uid, {}
# create the mail.template on mail.group model
group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0]
email_template = self.registry('mail.template')
email_template_id = email_template.create(cr, uid, {
'model_id': group_model_id,
'name': 'Pigs Template',
'email_from': 'Raoul Grosbedon <raoul@example.com>',
'subject': '${object.name}',
'body_html': '${object.description}',
'user_signature': True,
'email_to': 'b@b.b, c@c.c',
'email_cc': 'd@d.d',
'partner_to': '${user.partner_id.id},%s,%s,-1' % (self.user_raoul.partner_id.id, self.user_bert.partner_id.id)
})
# not force send: email_recipients is not taken into account
msg_id = email_template.send_mail(cr, uid, email_template_id, self.group_pigs_id, context=context)
mail = self.mail_mail.browse(cr, uid, msg_id, context=context)
self.assertEqual(mail.subject, 'Pigs', 'email_template: send_mail: wrong subject')
self.assertEqual(mail.email_to, 'b@b.b, c@c.c', 'email_template: send_mail: wrong email_to')
self.assertEqual(mail.email_cc, 'd@d.d', 'email_template: send_mail: wrong email_cc')
self.assertEqual(
set([partner.id for partner in mail.recipient_ids]),
set((self.partner_admin_id, self.user_raoul.partner_id.id, self.user_bert.partner_id.id)),
'email_template: send_mail: wrong management of partner_to')
# force send: take email_recipients into account
email_template.send_mail(cr, uid, email_template_id, self.group_pigs_id, force_send=True, context=context)
sent_emails = self._build_email_kwargs_list
email_to_lst = [
['b@b.b', 'c@c.c'], ['Administrator <admin@yourcompany.example.com>'],
['Raoul Grosbedon <raoul@raoul.fr>'], ['Bert Tartignole <bert@bert.fr>']]
self.assertEqual(len(sent_emails), 4, 'email_template: send_mail: 3 valid email recipients + email_to -> should send 4 emails')
for email in sent_emails:
self.assertIn(email['email_to'], email_to_lst, 'email_template: send_mail: wrong email_recipients')
File diff suppressed because it is too large Load Diff
+95
View File
@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
from openerp.addons.mail.tests.common import TestMail
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.group'})
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.group'})
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.group'), ('res_model', '=', False)])
def test_message_follower_ids_commands(self):
# Create some dummy data on other groups to ensure they are not altered
group_dummy = self.env['mail.group'].with_context({'mail_create_nolog': True}).create({'name': 'Dummy group'})
self.env['mail.followers'].create({'res_model': 'mail.thread', 'res_id': group_dummy.id, 'partner_id': self.partner_1.id})
# Add 2 followers through the (4, ID) command
self.group_pigs.write({'message_follower_ids': [(4, self.partner_1.id), (4, self.partner_2.id)]})
self.assertEqual(self.group_pigs.message_follower_ids, self.partner_1 | self.partner_2)
# Remove 1 follower through the (3, ID) command
self.group_pigs.write({'message_follower_ids': [(3, self.partner_2.id)]})
self.assertEqual(self.group_pigs.message_follower_ids, self.partner_1)
# Set followers through the (6, 0, IDs) command
self.group_pigs.write({'message_follower_ids': [(6, 0, [self.partner_2.id, self.user_employee_2.partner_id.id])]})
self.assertEqual(self.group_pigs.message_follower_ids,
self.partner_2 | self.user_employee_2.partner_id)
# Add 1 follower through the (0, 0, values) command
self.group_pigs.write({'message_follower_ids': [(0, 0, {'name': 'Patrick Fiori'})]})
partner_patrick = self.env['res.partner'].search([('name', '=', 'Patrick Fiori')], limit=1)
self.assertEqual(self.group_pigs.message_follower_ids,
self.partner_2 | self.user_employee_2.partner_id | partner_patrick)
# Remove all followers through a (5, 0) command
self.group_pigs.write({'message_follower_ids': [(5, 0)]})
self.assertFalse(self.group_pigs.message_follower_ids)
# Test dummy data has not been altered
followers = self.env['mail.followers'].search([('res_model', '=', 'mail.thread'), ('res_id', '=', group_dummy.id)])
self.assertEqual(followers.mapped('partner_id'), self.partner_1, 'dummy data altered')
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, self.user_employee.partner_id)
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.group'),
('res_id', '=', self.group_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_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, self.user_employee.partner_id)
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.group'),
('res_id', '=', self.group_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, self.user_employee.partner_id)
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.group'),
('res_id', '=', self.group_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, self.user_employee.partner_id)
follower = self.env['mail.followers'].search([
('res_model', '=', 'mail.group'),
('res_id', '=', self.group_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)
def test_subscription_data(self):
self.group_pigs.message_subscribe_users(user_ids=[self.user_employee.id])
subtype_data = self.group_pigs.sudo(self.user_employee)._get_subscription_data(None, None)[self.group_pigs.id]['message_subtype_data']
self.assertEqual(set(subtype_data.keys()), set(['Discussions', 'mt_mg_def', 'mt_al_def', 'mt_mg_nodef', 'mt_al_nodef']), 'mail.group available subtypes incorrect')
self.assertTrue(subtype_data['Discussions']['followed'])
self.assertFalse(subtype_data['mt_mg_nodef']['followed'])
self.assertFalse(subtype_data['mt_al_nodef']['followed'])
+275 -456
View File
@@ -1,23 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.mail.tests.common import TestMail
from openerp.tools import mute_logger
@@ -25,6 +6,7 @@ import socket
MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>
To: {to}
cc: {cc}
Received: by mail1.openerp.com (Postfix, from userid 10002)
id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST)
From: {email_from}
@@ -88,7 +70,7 @@ Delivered-To: raoul@grosbedon.fr
Received: by mail1.grosbedon.com (Postfix, from userid 10002)
id E8166BFACA; Fri, 23 Aug 2013 13:18:01 +0200 (CEST)
X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail1.grosbedon.com
X-Spam-Level:
X-Spam-Level:
X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,FREEMAIL_FROM,
HTML_MESSAGE,RCVD_IN_DNSWL_LOW autolearn=unavailable version=3.3.1
Received: from mail-ie0-f173.google.com (mail-ie0-f173.google.com [209.85.223.173])
@@ -125,7 +107,7 @@ Content-Type: text/plain; charset=ISO-8859-1
Should create a multipart/mixed: from gmail, *bold*, with attachment.
--
--
Marcel Boitempoils.
--089e01536c4ed4d16d04e49b8e94
@@ -191,548 +173,385 @@ Content-Type: text/html;
--Apple-Mail=_9331E12B-8BD2-4EC7-B53E-01F3FBEC9227--
"""
class TestMailgateway(TestMail):
def test_00_message_parse(self):
""" Testing incoming emails parsing """
cr, uid = self.cr, self.uid
res = self.mail_thread.message_parse(cr, uid, MAIL_TEMPLATE_PLAINTEXT)
self.assertIn('Please call me as soon as possible this afternoon!', res.get('body', ''),
@mute_logger('openerp.addons.mail.mail_thread')
def test_message_parse(self):
""" Test parsing of various scenarios of incoming emails """
res = self.env['mail.thread'].message_parse(MAIL_TEMPLATE_PLAINTEXT)
self.assertIn('Please call me as soon as possible this afternoon!',
res.get('body', ''),
'message_parse: missing text in text/plain body after parsing')
res = self.mail_thread.message_parse(cr, uid, MAIL_TEMPLATE)
self.assertIn('<p>Please call me as soon as possible this afternoon!</p>', res.get('body', ''),
res = self.env['mail.thread'].message_parse(MAIL_TEMPLATE)
self.assertIn('<p>Please call me as soon as possible this afternoon!</p>',
res.get('body', ''),
'message_parse: missing html in multipart/alternative body after parsing')
res = self.mail_thread.message_parse(cr, uid, MAIL_MULTIPART_MIXED)
self.assertNotIn('Should create a multipart/mixed: from gmail, *bold*, with attachment', res.get('body', ''),
res = self.env['mail.thread'].message_parse(MAIL_MULTIPART_MIXED)
self.assertNotIn('Should create a multipart/mixed: from gmail, *bold*, with attachment',
res.get('body', ''),
'message_parse: text version should not be in body after parsing multipart/mixed')
self.assertIn('<div dir="ltr">Should create a multipart/mixed: from gmail, <b>bold</b>, with attachment.<br clear="all"><div><br></div>', res.get('body', ''),
self.assertIn('<div dir="ltr">Should create a multipart/mixed: from gmail, <b>bold</b>, with attachment.<br clear="all"><div><br></div>',
res.get('body', ''),
'message_parse: html version should be in body after parsing multipart/mixed')
res = self.mail_thread.message_parse(cr, uid, MAIL_MULTIPART_MIXED_TWO)
self.assertNotIn('First and second part', res.get('body', ''),
res = self.env['mail.thread'].message_parse(MAIL_MULTIPART_MIXED_TWO)
self.assertNotIn('First and second part',
res.get('body', ''),
'message_parse: text version should not be in body after parsing multipart/mixed')
self.assertIn('First part', res.get('body', ''),
self.assertIn('First part',
res.get('body', ''),
'message_parse: first part of the html version should be in body after parsing multipart/mixed')
self.assertIn('Second part', res.get('body', ''),
self.assertIn('Second part',
res.get('body', ''),
'message_parse: second part of the html version should be in body after parsing multipart/mixed')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_10_message_process(self):
""" Testing incoming emails processing. """
cr, uid, user_raoul = self.cr, self.uid, self.user_raoul
def test_message_process_alias_basic(self):
""" Incoming email on an alias creating a new record + message_new + message details """
new_groups = self.format_and_process(MAIL_TEMPLATE, subject='My Frogs', to='groups@example.com, other@gmail.com')
def format_and_process(template, to='groups@example.com, other@gmail.com', subject='Frogs',
extra='', email_from='Sylvie Lelitre <test.sylvie.lelitre@agrolait.com>',
msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>',
model=None):
self.assertEqual(self.mail_group.search(cr, uid, [('name', '=', subject)]), [])
mail = template.format(to=to, subject=subject, extra=extra, email_from=email_from, msg_id=msg_id)
self.mail_thread.message_process(cr, uid, model, mail)
return self.mail_group.search(cr, uid, [('name', '=', subject)])
# --------------------------------------------------
# Data creation
# --------------------------------------------------
# groups@.. will cause the creation of new mail groups
self.mail_group_model_id = self.ir_model.search(cr, uid, [('model', '=', 'mail.group')])[0]
alias_id = self.mail_alias.create(cr, uid, {
'alias_name': 'groups',
'alias_user_id': False,
'alias_model_id': self.mail_group_model_id,
'alias_parent_model_id': self.mail_group_model_id,
'alias_parent_thread_id': self.group_pigs_id,
'alias_contact': 'everyone'})
# --------------------------------------------------
# Test1: new record creation
# --------------------------------------------------
# Do: incoming mail from an unknown partner on an alias creates a new mail_group "frogs"
self._init_mock_build_email()
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
sent_emails = self._build_email_kwargs_list
# Test: one group created by mailgateway administrator
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
res = self.mail_group.get_metadata(cr, uid, [frog_group.id])[0].get('create_uid') or [None]
self.assertEqual(res[0], uid,
'message_process: group should have been created by uid as alias_user__id is False on the alias')
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.group 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')
# Test: one message that is the incoming email
self.assertEqual(len(frog_group.message_ids), 1,
self.assertEqual(len(new_groups.message_ids), 1,
'message_process: newly created group should have the incoming email in message_ids')
msg = frog_group.message_ids[0]
self.assertEqual('Frogs', msg.subject,
msg = new_groups.message_ids[0]
self.assertEqual(msg.subject, 'My Frogs',
'message_process: newly created group should have the incoming email as first message')
self.assertIn('Please call me as soon as possible this afternoon!', msg.body,
'message_process: newly created group should have the incoming email as first message')
self.assertEqual('email', msg.type,
self.assertEqual(msg.type, 'email',
'message_process: newly created group should have an email as first message')
self.assertEqual('Discussions', msg.subtype_id.name,
self.assertEqual(msg.subtype_id, self.env.ref('mail.mt_comment'),
'message_process: newly created group should not have a log first message but an email')
# Test: message: unknown email address -> message has email_from, not author_id
self.assertFalse(msg.author_id,
'message_process: message on created group should not have an author_id')
self.assertIn('test.sylvie.lelitre@agrolait.com', msg.email_from,
'message_process: message on created group should have an email_from')
# Test: followers: nobody
self.assertEqual(len(frog_group.message_follower_ids), 0, 'message_process: newly create group should not have any follower')
# Test: sent emails: no-one
self.assertEqual(len(sent_emails), 0,
'message_process: should create emails without any follower added')
# Data: unlink group
frog_group.unlink()
# Do: incoming email from an unknown partner on a Partners only alias -> bounce
self._init_mock_build_email()
self.mail_alias.write(cr, uid, [alias_id], {'alias_contact': 'partners'})
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other2@gmail.com')
# Test: no group created
self.assertTrue(len(frog_groups) == 0)
# Test: email bounced
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 1,
# Test: sent emails: no-one
self.assertEqual(len(self._mails), 0,
'message_process: should create emails without any follower added')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_alias_user_id(self):
""" Test alias ownership """
self.alias.write({'alias_user_id': self.user_employee.id})
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.group 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')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_email_email_from(self):
""" Incoming email: not recognized author: email_from, no author_id, no followers """
new_groups = self.format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
self.assertFalse(new_groups.message_ids[0].author_id,
'message_process: unrecognized email -> no author_id')
self.assertIn('test.sylvie.lelitre@agrolait.com', new_groups.message_ids[0].email_from,
'message_process: unrecognized email -> email_from')
self.assertEqual(len(new_groups.message_follower_ids), 0,
'message_process: newly create group should not have any follower')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_email_author(self):
""" Incoming email: recognized author: email_from, author_id, added as follower """
new_groups = self.format_and_process(MAIL_TEMPLATE, email_from='Valid Lelitre <valid.lelitre@agrolait.com>', to='groups@example.com, valid.other@gmail.com')
self.assertEqual(new_groups.message_ids[0].author_id, self.partner_1,
'message_process: recognized email -> author_id')
self.assertIn('Valid Lelitre <valid.lelitre@agrolait.com>', new_groups.message_ids[0].email_from,
'message_process: recognized email -> email_from')
self.assertEqual(new_groups.message_follower_ids, self.partner_1,
'message_process: recognized email -> added as follower')
self.assertEqual(len(self._mails), 0,
'message_process: no bounce or notificatoin email should be sent with follower = author')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models', 'openerp.addons.mail.mail_mail')
def test_message_process_alias_partners_bounce(self):
""" Incoming email from an unknown partner on a Partners only alias -> bounce """
self.alias.write({'alias_contact': 'partners'})
# Test: no group created, email bounced
new_groups = self.format_and_process(MAIL_TEMPLATE, subject='New Frogs', to='groups@example.com, other@gmail.com')
self.assertTrue(len(new_groups) == 0)
self.assertEqual(len(self._mails), 1,
'message_process: incoming email on Partners alias should send a bounce email')
self.assertIn('Frogs', sent_emails[0].get('subject'),
self.assertIn('New Frogs', self._mails[0].get('subject'),
'message_process: bounce email on Partners alias should contain the original subject')
self.assertIn('test.sylvie.lelitre@agrolait.com', sent_emails[0].get('email_to'),
self.assertIn('test.sylvie.lelitre@agrolait.com', self._mails[0].get('email_to'),
'message_process: bounce email on Partners alias should have original email sender as recipient')
# Do: incoming email from an unknown partner on a Followers only alias -> bounce
self._init_mock_build_email()
self.mail_alias.write(cr, uid, [alias_id], {'alias_contact': 'followers'})
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other3@gmail.com')
# Test: no group created
self.assertTrue(len(frog_groups) == 0)
# Test: email bounced
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 1,
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models', 'openerp.addons.mail.mail_mail')
def test_message_process_alias_followers_bounce(self):
""" 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_group_model.id,
'alias_parent_thread_id': self.group_pigs.id})
# Test: unknown on followers alias -> bounce
new_groups = self.format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
self.assertEqual(len(new_groups), 0, 'message_process: should have bounced')
self.assertEqual(len(self._mails), 1,
'message_process: incoming email on Followers alias should send a bounce email')
self.assertIn('Frogs', sent_emails[0].get('subject'),
'message_process: bounce email on Followers alias should contain the original subject')
self.assertIn('test.sylvie.lelitre@agrolait.com', sent_emails[0].get('email_to'),
'message_process: bounce email on Followers alias should have original email sender as recipient')
# Do: incoming email from a known partner on a Partners alias -> ok (+ test on alias.user_id)
self.mail_alias.write(cr, uid, [alias_id], {'alias_user_id': self.user_raoul_id, 'alias_contact': 'partners'})
p1id = self.res_partner.create(cr, uid, {'name': 'Sylvie Lelitre', 'email': 'test.sylvie.lelitre@agrolait.com'})
p2id = self.res_partner.create(cr, uid, {'name': 'Other Poilvache', 'email': 'other4@gmail.com'})
# Test: partner on followers alias -> bounce
self._init_mock_build_email()
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other4@gmail.com')
sent_emails = self._build_email_kwargs_list
# Test: one group created by Raoul
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
res = self.mail_group.get_metadata(cr, uid, [frog_group.id])[0].get('create_uid') or [None]
self.assertEqual(res[0], self.user_raoul_id,
'message_process: group should have been created by alias_user_id')
new_groups = self.format_and_process(MAIL_TEMPLATE, email_from='Valid Lelitre <valid.lelitre@agrolait.com>', to='groups@example.com, other@gmail.com')
self.assertTrue(len(new_groups) == 0, 'message_process: should have bounced')
self.assertEqual(len(self._mails), 1,
'message_process: incoming email on Followers alias should send a bounce email')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_alias_partner(self):
""" Incoming email from a known partner on a Partners alias -> ok (+ test on alias.user_id) """
self.alias.write({'alias_contact': 'partners'})
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.group should have been created')
# Test: one message that is the incoming email
self.assertEqual(len(frog_group.message_ids), 1,
self.assertEqual(len(new_groups.message_ids), 1,
'message_process: newly created group should have the incoming email in message_ids')
msg = frog_group.message_ids[0]
# Test: message: author found
self.assertEqual(p1id, msg.author_id.id,
'message_process: message on created group should have Sylvie as author_id')
self.assertIn('Sylvie Lelitre <test.sylvie.lelitre@agrolait.com>', msg.email_from,
'message_process: message on created group should have have an email_from')
# Test: author (not recipient and not Raoul (as alias owner)) added as follower
frog_follower_ids = set([p.id for p in frog_group.message_follower_ids])
self.assertEqual(frog_follower_ids, set([p1id]),
'message_process: newly created group should have 1 follower (author, not creator, not recipients)')
# Test: sent emails: no-one, no bounce effet
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 0,
'message_process: should not bounce incoming emails')
# Data: unlink group
frog_group.unlink()
# Do: incoming email from a not follower Partner on a Followers only alias -> bounce
self._init_mock_build_email()
self.mail_alias.write(cr, uid, [alias_id], {'alias_user_id': False, 'alias_contact': 'followers'})
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other5@gmail.com')
# Test: no group created
self.assertTrue(len(frog_groups) == 0)
# Test: email bounced
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 1,
'message_process: incoming email on Partners alias should send a bounce email')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_alias_followers(self):
""" 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_group_model.id,
'alias_parent_thread_id': self.group_pigs.id})
self.group_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')
# Do: incoming email from a parent document follower on a Followers only alias -> ok
self._init_mock_build_email()
self.mail_group.message_subscribe(cr, uid, [self.group_pigs_id], [p1id])
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other6@gmail.com')
# Test: one group created by Raoul (or Sylvie maybe, if we implement it)
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: one message that is the incoming email
self.assertEqual(len(frog_group.message_ids), 1,
'message_process: newly created group should have the incoming email in message_ids')
# Test: author (and not recipient) added as follower
frog_follower_ids = set([p.id for p in frog_group.message_follower_ids])
self.assertEqual(frog_follower_ids, set([p1id]),
'message_process: newly created group should have 1 follower (author, not creator, not recipients)')
# Test: sent emails: no-one, no bounce effet
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 0,
'message_process: should not bounce incoming emails')
self.assertEqual(len(new_groups), 1, 'message_process: a new mail.group should have been created')
# --------------------------------------------------
# Test2: update-like alias
# --------------------------------------------------
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models', 'openerp.addons.mail.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})
# Do: Pigs alias is restricted, should bounce
self._init_mock_build_email()
self.mail_group.write(cr, uid, [frog_group.id], {'alias_name': 'frogs', 'alias_contact': 'followers', 'alias_force_thread_id': frog_group.id})
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com',
msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>',
to='frogs@example.com>', subject='Re: news')
# Test: no group 'Re: news' created, still only 1 Frogs group
self.assertEqual(len(frog_groups), 0,
self.group_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>',
to='groups@example.com>', subject='Re: cats')
# 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')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
self.assertEqual(len(frog_groups), 1,
'message_process: reply on Frogs should not have created a duplicate group with old subject')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: email bounced
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 1,
'message_process: incoming email on Followers alias should send a bounce email')
self.assertIn('Re: news', sent_emails[0].get('subject'),
'message_process: bounce email on Followers alias should contain the original subject')
# Do: Pigs alias is restricted, should accept Followers
self._init_mock_build_email()
self.mail_group.message_subscribe(cr, uid, [frog_group.id], [p2id])
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com',
msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>',
to='frogs@example.com>', subject='Re: cats')
# Test: no group 'Re: news' created, still only 1 Frogs group
self.assertEqual(len(frog_groups), 0,
'message_process: reply on Frogs should not have created a new group with new subject')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
self.assertEqual(len(frog_groups), 1,
'message_process: reply on Frogs should not have created a duplicate group with old subject')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: one new message
self.assertEqual(len(frog_group.message_ids), 2, 'message_process: group should contain 2 messages after reply')
# Test: sent emails: 1 (Sylvie copy of the incoming email, but no bounce)
sent_emails = self._build_email_kwargs_list
self.assertEqual(len(sent_emails), 1,
self.assertEqual(len(self.group_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('test.sylvie.lelitre@agrolait.com', sent_emails[0].get('email_to')[0],
self.assertIn('valid.lelitre@agrolait.com', self._mails[0].get('email_to')[0],
'message_process: email should be sent to Sylvie')
self.mail_group.message_unsubscribe(cr, uid, [frog_group.id], [p2id])
# --------------------------------------------------
# Test3: discussion and replies
# --------------------------------------------------
# Do: even with a wrong destination, a reply should end up in the correct thread
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com',
msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>',
to='erroneous@example.com>', subject='Re: news',
extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>\n')
# Test: no group 'Re: news' created, still only 1 Frogs group
self.assertEqual(len(frog_groups), 0,
'message_process: reply on Frogs should not have created a new group with new subject')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
self.assertEqual(len(frog_groups), 1,
'message_process: reply on Frogs should not have created a duplicate group with old subject')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: one new message
self.assertEqual(len(frog_group.message_ids), 3, 'message_process: group should contain 3 messages after reply')
# Test: author (and not recipient) added as follower
frog_follower_ids = set([p.id for p in frog_group.message_follower_ids])
self.assertEqual(frog_follower_ids, set([p1id, p2id]),
self.assertEqual(self.group_public.message_follower_ids, self.partner_1 | self.partner_2,
'message_process: after reply, group should have 2 followers')
# Do: incoming email with ref holding model / res_id but that does not match any message in the thread: must raise since OpenERP saas-3
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_in_reply_to(self):
""" Incoming email using in-rely-to should go into the right destination event with a wrong destination """
self.format_and_process(
MAIL_TEMPLATE, email_from='valid.other@gmail.com',
msg_id='<1198923581.41972151344608186800.JavaMail.diff1@agrolait.com>',
to='erroneous@example.com>', subject='Re: news',
extra='In-Reply-To: %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.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_references(self):
""" Incoming email using in-rely-to should go into the right destination event with a wrong destination """
self.format_and_process(
MAIL_TEMPLATE, to='erroneous@example.com',
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.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_model_res_id(self):
""" Incoming email with ref holding model / res_id but that does not match any message in the thread: must raise since OpenERP saas-3 """
self.assertRaises(ValueError,
format_and_process,
MAIL_TEMPLATE, email_from='other5@gmail.com',
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.group@example.com>' % frog_group.id,
msg_id='<1.1.JavaMail.new@agrolait.com>')
extra='In-Reply-To: <12321321-openerp-%d-mail.group@%s>' % (self.group_public.id, socket.gethostname()),
msg_id='<1198923581.41972151344608186802.JavaMail.diff1@agrolait.com>')
# When 6.1 messages are present, compat mode is available
# Create a fake 6.1 message
tmp_msg_id = self.mail_message.create(cr, uid, {'model': 'mail.group', 'res_id': frog_group.id})
self.mail_message.write(cr, uid, [tmp_msg_id], {'message_id': False})
# when 6.1 messages are present, compat mode is available
self.fake_email.write({'message_id': False})
# Do: compat mode accepts partial-matching emails
frog_groups = format_and_process(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.group@%s>' % (frog_group.id, socket.gethostname()))
self.mail_message.unlink(cr, uid, [tmp_msg_id])
# Test: no group 'Re: news' created, still only 1 Frogs group
self.assertEqual(len(frog_groups), 0,
'message_process: reply on Frogs should not have created a new group with new subject')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
self.assertEqual(len(frog_groups), 1,
'message_process: reply on Frogs should not have created a duplicate group with old subject')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: one new message
self.assertEqual(len(frog_group.message_ids), 4, 'message_process: group should contain 4 messages after reply')
frog_groups = self.format_and_process(
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.group@%s>' % (self.group_public.id, socket.gethostname()))
# 6.1 compat mode should not work if hostname does not match!
tmp_msg_id = self.mail_message.create(cr, uid, {'model': 'mail.group', 'res_id': frog_group.id})
self.mail_message.write(cr, uid, [tmp_msg_id], {'message_id': False})
# 3''. 6.1 compat mode should not work if hostname does not match!
self.assertRaises(ValueError,
format_and_process,
self.format_and_process,
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.group@neighbor.com>' % frog_group.id)
self.mail_message.unlink(cr, uid, [tmp_msg_id])
extra='In-Reply-To: <12321321-openerp-%d-mail.group@neighbor.com>' % frog_groups.id)
# 4. Subject contains [<ID>] + model passed to message+process -> only attached to group, but not to mail (not in msg1.child_ids)
self.format_and_process(
MAIL_TEMPLATE,
to='erroneous@example.com', email_from='other6@gmail.com',
extra='', subject='Re: [%s] 1' % self.group_public.id, model='mail.group',
msg_id='<1198923581.41972151344608186803.JavaMail.5@agrolait.com>')
# Test created messages
self.assertEqual(len(self.group_public.message_ids), 3, 'message_process: group should contain 6 messages')
self.assertEqual(len(self.group_public.message_ids[0].child_ids), 0, 'message_process: msg1 should not have children')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.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,})
# Post a base message
frog_groups = self.format_and_process(
MAIL_TEMPLATE, email_from='valid.other@gmail.com', subject='Re: super cats',
msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>')
# Do: due to some issue, same email goes back into the mailgateway
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com',
msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>',
subject='Re: news', extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>\n')
frog_groups = self.format_and_process(
MAIL_TEMPLATE, email_from='other4@gmail.com', subject='Re: news',
msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>',
extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>\n')
# Test: no group 'Re: news' created, still only 1 Frogs group
self.assertEqual(len(frog_groups), 0,
'message_process: reply on Frogs should not have created a new group with new subject')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
self.assertEqual(len(frog_groups), 1,
'message_process: reply on Frogs should not have created a duplicate group with old subject')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: no new message
self.assertEqual(len(frog_group.message_ids), 4, 'message_process: message with already existing message_id should not have been duplicated')
self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: message with already existing message_id should not have been duplicated')
# Test: message_id is still unique
msg_ids = self.mail_message.search(cr, uid, [('message_id', 'ilike', '<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>')])
self.assertEqual(len(msg_ids), 1,
no_of_msg = self.env['mail.message'].search_count([('message_id', 'ilike', '<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>')])
self.assertEqual(no_of_msg, 1,
'message_process: message with already existing message_id should not have been duplicated')
# --------------------------------------------------
# Test4: email_from and partner finding
# --------------------------------------------------
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_partner_find(self):
""" Finding the partner based on email, based on partner / user / follower """
from_1 = self.env['res.partner'].create({'name': 'A', 'email': 'from.test@example.com'})
# Data: extra partner with Raoul's email -> test the 'better author finding'
extra_partner_id = self.res_partner.create(cr, uid, {'name': 'A-Raoul', 'email': 'test_raoul@email.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(partner_ids=[from_1.id])
# Do: post a new message, with a known partner -> duplicate emails -> partner
format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik <test_raoul@email.com>',
subject='Re: news (2)',
msg_id='<1198923581.41972151344608186760.JavaMail.new1@agrolait.com>',
extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: author is A-Raoul (only existing)
self.assertEqual(frog_group.message_ids[0].author_id.id, extra_partner_id,
'message_process: email_from -> author_id wrong')
from_2 = self.env['res.users'].with_context({'no_reset_password': True}).create({'name': 'B', 'login': 'B', 'email': 'from.test@example.com'})
# Do: post a new message with a non-existant email that is a substring of a partner email
format_and_process(MAIL_TEMPLATE, email_from='Not really Lombrik Lubrik <oul@email.com>',
subject='Re: news (2)',
msg_id='<zzzbbbaaaa@agrolait.com>',
extra='In-Reply-To: <1198923581.41972151344608186760.JavaMail@agrolait.com>\n')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: author must not be set, otherwise the system is confusing different users
self.assertFalse(frog_group.message_ids[0].author_id, 'message_process: email_from -> mismatching author_id')
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(partner_ids=[from_2.id])
# Do: post a new message, with a known partner -> duplicate emails -> user
frog_group.message_unsubscribe([extra_partner_id])
self.res_users.write(cr, uid, self.user_raoul_id, {'email': 'test_raoul@email.com'})
format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik <test_raoul@email.com>',
to='groups@example.com', subject='Re: news (3)',
msg_id='<1198923581.41972151344608186760.JavaMail.new2@agrolait.com>',
extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: author is Raoul (user), not A-Raoul
self.assertEqual(frog_group.message_ids[0].author_id.id, self.partner_raoul_id,
'message_process: email_from -> author_id wrong')
from_3 = self.env['res.partner'].create({'name': 'C', 'email': 'from.test@example.com'})
self.group_public.message_subscribe(partner_ids=[from_3.id])
# Do: post a new message, with a known partner -> duplicate emails -> partner because is follower
frog_group.message_unsubscribe([self.partner_raoul_id])
frog_group.message_subscribe([extra_partner_id])
raoul_email = self.user_raoul.email
self.res_users.write(cr, uid, self.user_raoul_id, {'email': 'test_raoul@email.com'})
format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik <test_raoul@email.com>',
to='groups@example.com', subject='Re: news (3)',
msg_id='<1198923581.41972151344608186760.JavaMail.new3@agrolait.com>',
extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>')
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
# Test: author is Raoul (user), not A-Raoul
self.assertEqual(frog_group.message_ids[0].author_id.id, extra_partner_id,
'message_process: email_from -> author_id wrong')
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.res_users.write(cr, uid, self.user_raoul_id, {'email': raoul_email})
# --------------------------------------------------
# Test5: misc gateway features
# --------------------------------------------------
# Do: incoming email with model that does not accepts incoming emails must raise
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_crash_wrong_model(self):
""" Incoming email with model that does not accepts incoming emails must raise """
self.assertRaises(ValueError,
format_and_process,
self.format_and_process,
MAIL_TEMPLATE,
to='noone@example.com', subject='spam', extra='', model='res.country',
msg_id='<1198923581.41972151344608186760.JavaMail.new4@agrolait.com>')
# Do: incoming email without model and without alias must raise
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_crash_no_data(self):
""" Incoming email without model and without alias must raise """
self.assertRaises(ValueError,
format_and_process,
self.format_and_process,
MAIL_TEMPLATE,
to='noone@example.com', subject='spam', extra='',
msg_id='<1198923581.41972151344608186760.JavaMail.new5@agrolait.com>')
# Do: incoming email with model that accepting incoming emails as fallback
frog_groups = format_and_process(MAIL_TEMPLATE,
to='noone@example.com',
subject='Spammy', extra='', model='mail.group',
msg_id='<1198923581.41972151344608186760.JavaMail.new6@agrolait.com>')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
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.group',
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.group')
# Do: incoming email in plaintext should be stored as html
frog_groups = format_and_process(MAIL_TEMPLATE_PLAINTEXT,
to='groups@example.com', subject='Frogs Return', extra='',
msg_id='<deadcafe.1337@smtp.agrolait.com>')
# Test: one group created with one message
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_message_process_plain_text(self):
""" Incoming email in plaintext should be stored as html """
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.group should have been created')
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
msg = frog_group.message_ids[0]
# Test: plain text content should be wrapped and stored as html
msg = frog_groups.message_ids[0]
self.assertIn('<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>', msg.body,
'message_process: plaintext incoming email incorrectly parsed')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_20_thread_parent_resolution(self):
""" Testing parent/child relationships are correctly established when processing incoming mails """
cr, uid = self.cr, self.uid
def format(template, to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1',
extra='', email_from='Sylvie Lelitre <test.sylvie.lelitre@agrolait.com>',
msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>'):
return template.format(to=to, subject=subject, extra=extra, email_from=email_from, msg_id=msg_id)
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
msg1 = group_pigs.message_post(body='My Body', subject='1')
msg2 = group_pigs.message_post(body='My Body', subject='2')
msg1, msg2 = self.mail_message.browse(cr, uid, [msg1, msg2])
self.assertTrue(msg1.message_id, "message_process: new message should have a proper message_id")
# Reply to msg1, make sure the reply is properly attached using the various reply identification mechanisms
# 0. Direct alias match
reply_msg1 = format(MAIL_TEMPLATE, to='Pretty Pigs <group+pigs@example.com>',
extra='In-Reply-To: %s' % msg1.message_id,
msg_id='<1198923581.41972151344608186760.JavaMail.2@agrolait.com>')
self.mail_group.message_process(cr, uid, None, reply_msg1)
# 1. In-Reply-To header
reply_msg2 = format(MAIL_TEMPLATE, to='erroneous@example.com',
extra='In-Reply-To: %s' % msg1.message_id,
msg_id='<1198923581.41972151344608186760.JavaMail.3@agrolait.com>')
self.mail_group.message_process(cr, uid, None, reply_msg2)
# 2. References header
reply_msg3 = format(MAIL_TEMPLATE, to='erroneous@example.com',
extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id,
msg_id='<1198923581.41972151344608186760.JavaMail.4@agrolait.com>')
self.mail_group.message_process(cr, uid, None, reply_msg3)
# 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, but not to mail (not in msg1.child_ids)
reply_msg4 = format(MAIL_TEMPLATE, to='erroneous@example.com',
extra='', subject='Re: [%s] 1' % self.group_pigs_id,
msg_id='<1198923581.41972151344608186760.JavaMail.5@agrolait.com>')
self.mail_group.message_process(cr, uid, 'mail.group', reply_msg4)
group_pigs.refresh()
msg1.refresh()
self.assertEqual(6, len(group_pigs.message_ids), 'message_process: group should contain 6 messages')
self.assertEqual(3, len(msg1.child_ids), 'message_process: msg1 should have 3 children now')
def test_30_private_discussion(self):
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models', 'openerp.addons.mail.mail_mail')
def test_private_discussion(self):
""" Testing private discussion between partners. """
cr, uid = self.cr, self.uid
def format(template, to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1',
extra='', email_from='Sylvie Lelitre <test.sylvie.lelitre@agrolait.com>',
msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>'):
return template.format(to=to, subject=subject, extra=extra, email_from=email_from, msg_id=msg_id)
msg1_pids = [self.user_employee_2.partner_id.id, self.partner_1.id]
# Do: Raoul writes to Bert and Administrator, with a thread_model in context that should not be taken into account
msg1_pids = [self.partner_admin_id, self.partner_bert_id]
msg1_id = self.mail_thread.message_post(
cr, self.user_raoul_id, False,
partner_ids=msg1_pids,
subtype='mail.mt_comment',
context={'thread_model': 'mail.group'}
)
msg1_id = self.env['mail.thread'].with_context({
'thread_model': 'mail.group'
}).sudo(self.user_employee).message_post(partner_ids=msg1_pids, subtype='mail.mt_comment')
# Test: message recipients
msg = self.mail_message.browse(cr, uid, msg1_id)
msg_pids = [p.id for p in msg.partner_ids]
msg_nids = [p.id for p in msg.notified_partner_ids]
test_pids = msg1_pids
test_nids = msg1_pids
self.assertEqual(set(msg_pids), set(test_pids),
msg = self.env['mail.message'].browse(msg1_id)
self.assertEqual(msg.partner_ids, self.user_employee_2.partner_id | self.partner_1,
'message_post: private discussion: incorrect recipients')
self.assertEqual(set(msg_nids), set(test_nids),
self.assertEqual(msg.notified_partner_ids, self.user_employee_2.partner_id | self.partner_1,
'message_post: private discussion: incorrect notified recipients')
self.assertEqual(msg.model, False,
'message_post: private discussion: context key "thread_model" not correctly ignored when having no res_id')
# Test: message-id
self.assertIn('openerp-private', msg.message_id,
'message_post: private discussion: message-id should contain the private keyword')
self.assertIn('openerp-private', msg.message_id, 'message_post: private discussion: message-id should contain the private keyword')
# Do: Bert replies through mailgateway (is a customer)
reply_message = format(MAIL_TEMPLATE, to='not_important@mydomain.com',
email_from='bert@bert.fr',
extra='In-Reply-To: %s' % msg.message_id,
msg_id='<test30.JavaMail.0@agrolait.com>')
self.mail_thread.message_process(cr, uid, None, reply_message)
self.format_and_process(
MAIL_TEMPLATE, to='not_important@mydomain.com', email_from='valid.lelitre@agrolait.com',
extra='In-Reply-To: %s' % msg.message_id, msg_id='<test30.JavaMail.0@agrolait.com>')
# Test: last mail_message created
msg2_id = self.mail_message.search(cr, uid, [], limit=1)[0]
msg = self.env['mail.message'].search([], limit=1)
# Test: message recipients
msg = self.mail_message.browse(cr, uid, msg2_id)
msg_pids = [p.id for p in msg.partner_ids]
msg_nids = [p.id for p in msg.notified_partner_ids]
test_pids = [self.partner_admin_id, self.partner_raoul_id]
test_nids = test_pids
self.assertEqual(msg.author_id.id, self.partner_bert_id,
self.assertEqual(msg.author_id, self.partner_1,
'message_post: private discussion: wrong author through mailgatewya based on email')
self.assertEqual(set(msg_pids), set(test_pids),
self.assertEqual(msg.partner_ids, self.user_employee.partner_id | self.user_employee_2.partner_id,
'message_post: private discussion: incorrect recipients when replying')
self.assertEqual(set(msg_nids), set(test_nids),
self.assertEqual(msg.notified_partner_ids, self.user_employee.partner_id | self.user_employee_2.partner_id,
'message_post: private discussion: incorrect notified recipients when replying')
# Do: Bert replies through chatter (is a customer)
msg3_id = self.mail_thread.message_post(
cr, uid, False,
author_id=self.partner_bert_id,
parent_id=msg1_id, subtype='mail.mt_comment')
msg3_id = self.env['mail.thread'].message_post(author_id=self.partner_1.id, parent_id=msg1_id, subtype='mail.mt_comment')
# Test: message recipients
msg = self.mail_message.browse(cr, uid, msg3_id)
msg_pids = [p.id for p in msg.partner_ids]
msg_nids = [p.id for p in msg.notified_partner_ids]
test_pids = [self.partner_admin_id, self.partner_raoul_id]
test_nids = test_pids
self.assertEqual(set(msg_pids), set(test_pids),
msg = self.env['mail.message'].browse(msg3_id)
self.assertEqual(msg.partner_ids, self.user_employee.partner_id | self.user_employee_2.partner_id,
'message_post: private discussion: incorrect recipients when replying')
self.assertEqual(set(msg_nids), set(test_nids),
'message_post: private discussion: incorrect notified recipients when replying')
# Do: Administrator replies
msg3_id = self.mail_thread.message_post(cr, uid, False, parent_id=msg3_id, subtype='mail.mt_comment')
# Test: message recipients
msg = self.mail_message.browse(cr, uid, msg3_id)
msg_pids = [p.id for p in msg.partner_ids]
msg_nids = [p.id for p in msg.notified_partner_ids]
test_pids = [self.partner_bert_id, self.partner_raoul_id]
test_nids = test_pids
self.assertEqual(set(msg_pids), set(test_pids),
'message_post: private discussion: incorrect recipients when replying')
self.assertEqual(set(msg_nids), set(test_nids),
self.assertEqual(msg.notified_partner_ids, self.user_employee.partner_id | self.user_employee_2.partner_id,
'message_post: private discussion: incorrect notified recipients when replying')
+62 -54
View File
@@ -1,71 +1,79 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.mail.tests.common import TestMail
from openerp.exceptions import AccessError
from openerp.exceptions import except_orm
from openerp.tools import mute_logger
class TestMailGroup(TestMail):
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_00_mail_group_access_rights(self):
""" Testing mail_group access rights and basic mail_thread features """
cr, uid, user_noone_id, user_employee_id = self.cr, self.uid, self.user_noone_id, self.user_employee_id
def test_access_rights_public(self):
# Read public group -> ok
self.group_public.sudo(self.user_public).read()
# Do: Bert reads Jobs -> ok, public
self.mail_group.read(cr, user_noone_id, [self.group_jobs_id])
# Do: Bert read Pigs -> ko, restricted to employees
with self.assertRaises(AccessError):
self.mail_group.read(cr, user_noone_id, [self.group_pigs_id])
# Do: Raoul read Pigs -> ok, belong to employees
self.mail_group.read(cr, user_employee_id, [self.group_pigs_id])
# Read Pigs -> ko, restricted to employees
# TODO: Change the except_orm to Warning ( Because here it's call check_access_rule
# which still generate exception in except_orm.So we need to change all
# except_orm to warning in mail module.)
with self.assertRaises(except_orm):
self.group_pigs.sudo(self.user_public).read()
# Do: Bert creates a group -> ko, no access rights
with self.assertRaises(AccessError):
self.mail_group.create(cr, user_noone_id, {'name': 'Test'})
# Do: Raoul creates a restricted group -> ok
new_group_id = self.mail_group.create(cr, user_employee_id, {'name': 'Test'})
# Do: Bert added in followers, read -> ok, in followers
self.mail_group.message_subscribe_users(cr, uid, [new_group_id], [user_noone_id])
self.mail_group.read(cr, user_noone_id, [new_group_id])
# Read a private group when being a follower: ok
self.group_private.message_subscribe_users(user_ids=[self.user_public.id])
self.group_private.sudo(self.user_public).read()
# Do: Raoul reads Priv -> ko, private
# Create group: ko, no access rights
with self.assertRaises(AccessError):
self.mail_group.read(cr, user_employee_id, [self.group_priv_id])
# Do: Raoul added in follower, read -> ok, in followers
self.mail_group.message_subscribe_users(cr, uid, [self.group_priv_id], [user_employee_id])
self.mail_group.read(cr, user_employee_id, [self.group_priv_id])
self.env['mail.group'].sudo(self.user_public).create({'name': 'Test'})
# Do: Raoul write on Jobs -> ok
self.mail_group.write(cr, user_employee_id, [self.group_priv_id], {'name': 'modified'})
# Do: Bert cannot write on Private -> ko (read but no write)
# Update group: ko, no access rights
with self.assertRaises(AccessError):
self.mail_group.write(cr, user_noone_id, [self.group_priv_id], {'name': 're-modified'})
# Test: Bert cannot unlink the group
self.group_public.sudo(self.user_public).write({'name': 'Broutouschnouk'})
# Unlink group: ko, no access rights
with self.assertRaises(AccessError):
self.mail_group.unlink(cr, user_noone_id, [self.group_priv_id])
# Do: Raoul unlinks the group, there are no followers and messages left
self.mail_group.unlink(cr, user_employee_id, [self.group_priv_id])
fol_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', self.group_priv_id)])
self.assertFalse(fol_ids, 'unlinked document should not have any followers left')
msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_priv_id)])
self.assertFalse(msg_ids, 'unlinked document should not have any followers left')
self.group_public.sudo(self.user_public).unlink()
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_access_rights_groups(self):
# Employee read employee-based group: ok
# TODO Change the except_orm to Warning
self.group_pigs.sudo(self.user_employee).read()
# Employee can create a group
self.env['mail.group'].sudo(self.user_employee).create({'name': 'Test'})
# Employee update employee-based group: ok
self.group_pigs.sudo(self.user_employee).write({'name': 'modified'})
# Employee unlink employee-based group: ok
self.group_pigs.sudo(self.user_employee).unlink()
# Employee cannot read a private group
with self.assertRaises(except_orm):
self.group_private.sudo(self.user_employee).read()
# Employee cannot write on private
with self.assertRaises(AccessError):
self.group_private.sudo(self.user_employee).write({'name': 're-modified'})
def test_access_rights_followers_ko(self):
with self.assertRaises(AccessError):
self.group_private.sudo(self.user_portal).name
def test_access_rights_followers_portal(self):
# Do: Chell is added into Pigs followers and browse it -> ok for messages, ko for partners (no read permission)
self.group_private.message_subscribe_users(user_ids=[self.user_portal.id])
chell_pigs = self.group_private.sudo(self.user_portal)
trigger_read = chell_pigs.name
for message in chell_pigs.message_ids:
trigger_read = message.subject
for partner in chell_pigs.message_follower_ids:
if partner.id == self.user_portal.partner_id.id:
# Chell can read her own partner record
continue
# TODO Change the except_orm to Warning
with self.assertRaises(except_orm):
trigger_read = partner.name
+232 -384
View File
@@ -1,446 +1,294 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.mail.tests.common import TestMail
from openerp.exceptions import AccessError
from openerp.exceptions import except_orm
from openerp.tools import mute_logger
class TestMailMail(TestMail):
def test_00_partner_find_from_email(self):
""" Tests designed for partner fetch based on emails. """
cr, uid, user_raoul, group_pigs = self.cr, self.uid, self.user_raoul, self.group_pigs
# --------------------------------------------------
# Data creation
# --------------------------------------------------
# 1 - Partner ARaoul
p_a_id = self.res_partner.create(cr, uid, {'name': 'ARaoul', 'email': 'test@test.fr'})
# --------------------------------------------------
# CASE1: without object
# --------------------------------------------------
# Do: find partner with email -> first partner should be found
partner_info = self.mail_thread.message_partner_info_from_emails(cr, uid, None, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
self.assertEqual(partner_info['full_name'], 'Maybe Raoul <test@test.fr>',
'mail_thread: message_partner_info_from_emails did not handle email')
self.assertEqual(partner_info['partner_id'], p_a_id,
'mail_thread: message_partner_info_from_emails wrong partner found')
# Data: add some data about partners
# 2 - User BRaoul
p_b_id = self.res_partner.create(cr, uid, {'name': 'BRaoul', 'email': 'test@test.fr', 'user_ids': [(4, user_raoul.id)]})
# Do: find partner with email -> first user should be found
partner_info = self.mail_thread.message_partner_info_from_emails(cr, uid, None, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
self.assertEqual(partner_info['partner_id'], p_b_id,
'mail_thread: message_partner_info_from_emails wrong partner found')
# --------------------------------------------------
# CASE1: with object
# --------------------------------------------------
# Do: find partner in group where there is a follower with the email -> should be taken
self.mail_group.message_subscribe(cr, uid, [group_pigs.id], [p_b_id])
partner_info = self.mail_group.message_partner_info_from_emails(cr, uid, group_pigs.id, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
self.assertEqual(partner_info['partner_id'], p_b_id,
'mail_thread: message_partner_info_from_emails wrong partner found')
class TestMailMessage(TestMail):
def test_00_mail_message_values(self):
""" Tests designed for testing email values based on mail.message, aliases, ... """
cr, uid, user_raoul_id = self.cr, self.uid, self.user_raoul_id
def setUp(self):
super(TestMailMessage, self).setUp()
self.attachment = self.env['ir.attachment'].create({
'datas': 'My attachment'.encode('base64'),
'name': 'doc.txt',
'datas_fname': 'doc.txt'})
self.message = self.env['mail.message'].create({
'body': 'My Body',
'model': 'mail.group',
'res_id': self.group_private.id,
'attachment_ids': [(4, self.attachment.id)],
})
# Data: update + generic variables
reply_to1 = '_reply_to1@example.com'
reply_to2 = '_reply_to2@example.com'
email_from1 = 'from@example.com'
alias_domain = 'schlouby.fr'
raoul_from = 'Raoul Grosbedon <raoul@raoul.fr>'
raoul_from_alias = 'Raoul Grosbedon <raoul@schlouby.fr>'
raoul_reply_alias = 'YourCompany Pigs <group+pigs@schlouby.fr>'
def test_mail_message_values_basic(self):
self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink()
# --------------------------------------------------
# Case1: without alias_domain
# --------------------------------------------------
param_ids = self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.domain')])
self.registry('ir.config_parameter').unlink(cr, uid, param_ids)
msg = self.env['mail.message'].sudo(self.user_employee).create({
'reply_to': 'test.reply@example.com',
'email_from': 'test.from@example.com',
})
self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertEqual(msg.reply_to, 'test.reply@example.com')
self.assertEqual(msg.email_from, 'test.from@example.com')
# Do: free message; specified values > default values
msg_id = self.mail_message.create(cr, user_raoul_id, {'no_auto_thread': True, 'reply_to': reply_to1, 'email_from': email_from1})
msg = self.mail_message.browse(cr, user_raoul_id, msg_id)
# Test: message content
self.assertIn('reply_to', msg.message_id,
'mail_message: message_id should be specific to a mail_message with a given reply_to')
self.assertEqual(msg.reply_to, reply_to1,
'mail_message: incorrect reply_to: should come from values')
self.assertEqual(msg.email_from, email_from1,
'mail_message: incorrect email_from: should come from values')
def test_mail_message_values_default(self):
self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink()
# Do: create a mail_mail with the previous mail_message + specified reply_to
mail_id = self.mail_mail.create(cr, user_raoul_id, {'mail_message_id': msg_id, 'state': 'cancel', 'reply_to': reply_to2})
mail = self.mail_mail.browse(cr, user_raoul_id, mail_id)
# Test: mail_mail content
self.assertEqual(mail.reply_to, reply_to2,
'mail_mail: incorrect reply_to: should come from values')
self.assertEqual(mail.email_from, email_from1,
'mail_mail: incorrect email_from: should come from mail.message')
msg = self.env['mail.message'].sudo(self.user_employee).create({})
self.assertIn('-private', 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))
# Do: mail_message attached to a document
msg_id = self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_pigs_id})
msg = self.mail_message.browse(cr, user_raoul_id, msg_id)
# Test: message content
self.assertIn('mail.group', msg.message_id,
'mail_message: message_id should contain model')
self.assertIn('%s' % self.group_pigs_id, msg.message_id,
'mail_message: message_id should contain res_id')
self.assertEqual(msg.reply_to, raoul_from,
'mail_message: incorrect reply_to: should be Raoul')
self.assertEqual(msg.email_from, raoul_from,
'mail_message: incorrect email_from: should be Raoul')
def test_mail_message_values_alias(self):
alias_domain = 'example.com'
self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain)
self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink()
# --------------------------------------------------
# Case2: with alias_domain, without catchall alias
# --------------------------------------------------
self.registry('ir.config_parameter').set_param(cr, uid, 'mail.catchall.domain', alias_domain)
self.registry('ir.config_parameter').unlink(cr, uid, self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.alias')]))
msg = self.env['mail.message'].sudo(self.user_employee).create({})
self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertEqual(msg.reply_to, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain))
self.assertEqual(msg.email_from, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain))
# Update message
msg_id = self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_pigs_id})
msg = self.mail_message.browse(cr, user_raoul_id, msg_id)
# Test: generated reply_to
self.assertEqual(msg.reply_to, raoul_reply_alias,
'mail_mail: incorrect reply_to: should be Pigs alias')
def test_mail_message_values_alias_catchall(self):
alias_domain = 'example.com'
alias_catchall = 'pokemon'
self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain)
self.env['ir.config_parameter'].set_param('mail.catchall.alias', alias_catchall)
# Update message: test alias on email_from
msg_id = self.mail_message.create(cr, user_raoul_id, {})
msg = self.mail_message.browse(cr, user_raoul_id, msg_id)
# Test: generated reply_to
self.assertEqual(msg.reply_to, raoul_from_alias,
'mail_mail: incorrect reply_to: should be message email_from using Raoul alias')
msg = self.env['mail.message'].sudo(self.user_employee).create({})
self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one')
self.assertEqual(msg.reply_to, '%s <%s@%s>' % (self._company_name, alias_catchall, alias_domain))
self.assertEqual(msg.email_from, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain))
# --------------------------------------------------
# Case2: with alias_domain and catchall alias
# --------------------------------------------------
self.registry('ir.config_parameter').set_param(self.cr, self.uid, 'mail.catchall.alias', 'gateway')
def test_mail_message_values_document_no_alias(self):
self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink()
# Update message
msg_id = self.mail_message.create(cr, user_raoul_id, {})
msg = self.mail_message.browse(cr, user_raoul_id, msg_id)
# Test: generated reply_to
self.assertEqual(msg.reply_to, 'YourCompany <gateway@schlouby.fr>',
'mail_mail: reply_to should equal the catchall email alias')
msg = self.env['mail.message'].sudo(self.user_employee).create({
'model': 'mail.group',
'res_id': self.group_pigs.id
})
self.assertIn('-openerp-%d-mail.group' % 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>' % (self.user_employee.name, self.user_employee.email))
self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email))
# Do: create a mail_mail
mail_id = self.mail_mail.create(cr, uid, {'state': 'cancel', 'reply_to': 'someone@example.com'})
mail = self.mail_mail.browse(cr, uid, mail_id)
# Test: mail_mail content
self.assertEqual(mail.reply_to, 'someone@example.com',
'mail_mail: reply_to should equal the rpely_to given to create')
def test_mail_message_values_document_alias(self):
alias_domain = 'example.com'
self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain)
self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink()
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_10_mail_message_search_access_rights(self):
""" Testing mail_message.search() using specific _search implementation """
cr, uid, group_pigs_id = self.cr, self.uid, self.group_pigs_id
# Data: comment subtype for mail.message creation
ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'mail', 'mt_comment')
subtype_id = ref and ref[1] or False
msg = self.env['mail.message'].sudo(self.user_employee).create({
'model': 'mail.group',
'res_id': self.group_pigs.id
})
self.assertIn('-openerp-%d-mail.group' % 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._company_name, self.group_pigs.name, self.group_pigs.alias_name, alias_domain))
self.assertEqual(msg.email_from, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain))
# Data: Birds group, private
group_birds_id = self.mail_group.create(self.cr, self.uid, {'name': 'Birds', 'public': 'private'})
# Data: Raoul is member of Pigs
self.mail_group.message_subscribe(cr, uid, [group_pigs_id], [self.partner_raoul_id])
def test_mail_message_values_document_alias_catchall(self):
alias_domain = 'example.com'
alias_catchall = 'pokemon'
self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain)
self.env['ir.config_parameter'].set_param('mail.catchall.alias', alias_catchall)
msg = self.env['mail.message'].sudo(self.user_employee).create({
'model': 'mail.group',
'res_id': self.group_pigs.id
})
self.assertIn('-openerp-%d-mail.group' % 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._company_name, self.group_pigs.name, self.group_pigs.alias_name, alias_domain))
self.assertEqual(msg.email_from, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain))
def test_mail_message_values_no_auto_thread(self):
msg = self.env['mail.message'].sudo(self.user_employee).create({
'model': 'mail.group',
'res_id': self.group_pigs.id,
'no_auto_thread': True,
})
self.assertIn('reply_to', msg.message_id)
self.assertNotIn('mail.group', msg.message_id)
self.assertNotIn('-%d-' % self.group_pigs.id, msg.message_id)
@mute_logger('openerp.addons.mail.mail_mail')
def test_mail_message_access_search(self):
# Data: various author_ids, partner_ids, documents
msg_id1 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A', 'subtype_id': subtype_id})
msg_id2 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A+B', 'partner_ids': [(6, 0, [self.partner_bert_id])], 'subtype_id': subtype_id})
msg_id3 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A Pigs', 'model': 'mail.group', 'res_id': group_pigs_id, 'subtype_id': subtype_id})
msg_id4 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A+B Pigs', 'model': 'mail.group', 'res_id': group_pigs_id, 'partner_ids': [(6, 0, [self.partner_bert_id])], 'subtype_id': subtype_id})
msg_id5 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A+R Pigs', 'model': 'mail.group', 'res_id': group_pigs_id, 'partner_ids': [(6, 0, [self.partner_raoul_id])], 'subtype_id': subtype_id})
msg_id6 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A Birds', 'model': 'mail.group', 'res_id': group_birds_id, 'subtype_id': subtype_id})
msg_id7 = self.mail_message.create(cr, self.user_raoul_id, {'subject': '_Test', 'body': 'B', 'subtype_id': subtype_id})
msg_id8 = self.mail_message.create(cr, self.user_raoul_id, {'subject': '_Test', 'body': 'B+R', 'partner_ids': [(6, 0, [self.partner_raoul_id])], 'subtype_id': subtype_id})
msg1 = self.env['mail.message'].create({
'subject': '_Test', 'body': 'A', 'subtype_id': self.ref('mail.mt_comment')})
msg2 = self.env['mail.message'].create({
'subject': '_Test', 'body': 'A+B', 'subtype_id': self.ref('mail.mt_comment'),
'partner_ids': [(6, 0, [self.user_public.partner_id.id])]})
msg3 = self.env['mail.message'].create({
'subject': '_Test', 'body': 'A Pigs', 'subtype_id': False,
'model': 'mail.group', 'res_id': self.group_pigs.id})
msg4 = self.env['mail.message'].create({
'subject': '_Test', 'body': 'A+P Pigs', 'subtype_id': self.ref('mail.mt_comment'),
'model': 'mail.group', 'res_id': self.group_pigs.id,
'partner_ids': [(6, 0, [self.user_public.partner_id.id])]})
msg5 = self.env['mail.message'].create({
'subject': '_Test', 'body': 'A+E Pigs', 'subtype_id': self.ref('mail.mt_comment'),
'model': 'mail.group', 'res_id': self.group_pigs.id,
'partner_ids': [(6, 0, [self.user_employee.partner_id.id])]})
msg6 = self.env['mail.message'].create({
'subject': '_Test', 'body': 'A Birds', 'subtype_id': self.ref('mail.mt_comment'),
'model': 'mail.group', 'res_id': self.group_private.id})
msg7 = self.env['mail.message'].sudo(self.user_employee).create({
'subject': '_Test', 'body': 'B', 'subtype_id': self.ref('mail.mt_comment')})
msg8 = self.env['mail.message'].sudo(self.user_employee).create({
'subject': '_Test', 'body': 'B+E', 'subtype_id': self.ref('mail.mt_comment'),
'partner_ids': [(6, 0, [self.user_employee.partner_id.id])]})
# Test: Public: 2 messages (recipient)
messages = self.env['mail.message'].sudo(self.user_public).search([('subject', 'like', '_Test')])
self.assertEqual(messages, msg2 | msg4)
# Test: Employee: 3 messages on Pigs Raoul can read (employee can read group with default values)
messages = self.env['mail.message'].sudo(self.user_employee).search([('subject', 'like', '_Test'), ('body', 'ilike', 'A')])
self.assertEqual(messages, msg3 | msg4 | msg5)
# Test: Bert: 2 messages that have Bert in partner_ids
msg_ids = self.mail_message.search(cr, self.user_bert_id, [('subject', 'like', '_Test')])
self.assertEqual(set([msg_id2, msg_id4]), set(msg_ids), 'mail_message search failed')
# Test: Raoul: 3 messages on Pigs Raoul can read (employee can read group with default values), 0 on Birds (private group)
msg_ids = self.mail_message.search(cr, self.user_raoul_id, [('subject', 'like', '_Test'), ('body', 'like', 'A')])
self.assertEqual(set([msg_id3, msg_id4, msg_id5]), set(msg_ids), 'mail_message search failed')
# Test: Raoul: 3 messages on Pigs Raoul can read (employee can read group with default values), 0 on Birds (private group) + 2 messages as author
msg_ids = self.mail_message.search(cr, self.user_raoul_id, [('subject', 'like', '_Test')])
self.assertEqual(set([msg_id3, msg_id4, msg_id5, msg_id7, msg_id8]), set(msg_ids), 'mail_message search failed')
messages = self.env['mail.message'].sudo(self.user_employee).search([('subject', 'like', '_Test')])
self.assertEqual(messages, msg3 | msg4 | msg5 | msg7 | msg8)
# Test: Admin: all messages
msg_ids = self.mail_message.search(cr, uid, [('subject', 'like', '_Test')])
self.assertEqual(set([msg_id1, msg_id2, msg_id3, msg_id4, msg_id5, msg_id6, msg_id7, msg_id8]), set(msg_ids), 'mail_message search failed')
messages = self.env['mail.message'].search([('subject', 'like', '_Test')])
self.assertEqual(messages, msg1 | msg2 | msg3 | msg4 | msg5 | msg6 | msg7 | msg8)
# Test: Portal: 0 (no access to groups, not recipient)
messages = self.env['mail.message'].sudo(self.user_portal).search([('subject', 'like', '_Test')])
self.assertFalse(messages)
# Test: Portal: 2 messages (public group with a subtype)
self.group_pigs.write({'public': 'public'})
messages = self.env['mail.message'].sudo(self.user_portal).search([('subject', 'like', '_Test')])
self.assertEqual(messages, msg4 | msg5)
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_15_mail_message_check_access_rule(self):
""" Testing mail_message.check_access_rule() """
cr, uid = self.cr, self.uid
partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id
user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id
def test_mail_message_access_read_crash(self):
# TODO: Change the except_orm to Warning ( Because here it's call check_access_rule
# which still generate exception in except_orm.So we need to change all
# except_orm to warning in mail module.)
with self.assertRaises(except_orm):
self.message.sudo(self.user_employee).read()
# Prepare groups: Pigs (employee), Jobs (public)
pigs_msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message')
priv_msg_id = self.mail_group.message_post(cr, uid, self.group_priv_id, body='Message')
def test_mail_message_access_read_crash_portal(self):
with self.assertRaises(except_orm):
self.message.sudo(self.user_portal).read(['body', 'type', 'subtype_id'])
# prepare an attachment
attachment_id = self.ir_attachment.create(cr, uid, {'datas': 'My attachment'.encode('base64'), 'name': 'doc.txt', 'datas_fname': 'doc.txt'})
def test_mail_message_access_read_ok_portal(self):
self.message.write({'subtype_id': self.ref('mail.mt_comment'), 'res_id': self.group_public.id})
self.message.sudo(self.user_portal).read(['body', 'type', 'subtype_id'])
# ----------------------------------------
# CASE1: read
# ----------------------------------------
# Do: create a new mail.message
message_id = self.mail_message.create(cr, uid, {'body': 'My Body', 'attachment_ids': [(4, attachment_id)]})
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
with self.assertRaises(AccessError):
self.mail_message.read(cr, user_bert_id, message_id)
# Do: message is pushed to Bert
notif_id = self.mail_notification.create(cr, uid, {'message_id': message_id, 'partner_id': partner_bert_id})
# Test: Bert reads the message, ok because notification pushed
self.mail_message.read(cr, user_bert_id, message_id)
def test_mail_message_access_read_notification(self):
self.env['mail.notification'].create({'message_id': self.message.id, 'partner_id': self.user_employee.partner_id.id})
self.message.sudo(self.user_employee).read()
# Test: Bert downloads attachment, ok because he can read message
self.mail_message.download_attachment(cr, user_bert_id, message_id, attachment_id)
# Do: remove notification
self.mail_notification.unlink(cr, uid, notif_id)
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
with self.assertRaises(AccessError):
self.mail_message.read(cr, self.user_bert_id, message_id)
# Test: Bert downloads attachment, crash because he can't read message
with self.assertRaises(AccessError):
self.mail_message.download_attachment(cr, user_bert_id, message_id, attachment_id)
# Do: Bert is now the author
self.mail_message.write(cr, uid, [message_id], {'author_id': partner_bert_id})
# Test: Bert reads the message, ok because Bert is the author
self.mail_message.read(cr, user_bert_id, message_id)
# Do: Bert is not the author anymore
self.mail_message.write(cr, uid, [message_id], {'author_id': partner_raoul_id})
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
with self.assertRaises(AccessError):
self.mail_message.read(cr, user_bert_id, message_id)
# Do: message is attached to a document Bert can read, Jobs
self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_jobs_id})
self.env['mail.message'].sudo(self.user_employee).download_attachment(self.message.id, self.attachment.id)
def test_mail_message_access_read_author(self):
self.message.write({'author_id': self.user_employee.partner_id.id})
self.message.sudo(self.user_employee).read()
def test_mail_message_access_read_doc(self):
self.message.write({'model': 'mail.group', 'res_id': self.group_public.id})
# Test: Bert reads the message, ok because linked to a doc he is allowed to read
self.mail_message.read(cr, user_bert_id, message_id)
# Do: message is attached to a document Bert cannot read, Pigs
self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_pigs_id})
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
with self.assertRaises(AccessError):
self.mail_message.read(cr, user_bert_id, message_id)
# ----------------------------------------
# CASE2: create
# ----------------------------------------
self.message.sudo(self.user_employee).read()
@mute_logger('openerp.addons.base.ir.ir_model')
def test_mail_message_access_create_crash_public(self):
# Do: Bert creates a message on Pigs -> ko, no creation rights
with self.assertRaises(AccessError):
self.mail_message.create(cr, user_bert_id, {'model': 'mail.group', 'res_id': self.group_pigs_id, 'body': 'Test'})
self.env['mail.message'].sudo(self.user_public).create({'model': 'mail.group', 'res_id': self.group_pigs.id, 'body': 'Test'})
# Do: Bert create a message on Jobs -> ko, no creation rights
with self.assertRaises(AccessError):
self.mail_message.create(cr, user_bert_id, {'model': 'mail.group', 'res_id': self.group_jobs_id, 'body': 'Test'})
self.env['mail.message'].sudo(self.user_public).create({'model': 'mail.group', 'res_id': self.group_public.id, 'body': 'Test'})
def test_mail_message_access_create_crash(self):
# Do: Bert create a private message -> ko, no creation rights
with self.assertRaises(AccessError):
self.mail_message.create(cr, user_bert_id, {'body': 'Test'})
with self.assertRaises(except_orm):
self.env['mail.message'].sudo(self.user_employee).create({'model': 'mail.group', 'res_id': self.group_private.id, 'body': 'Test'})
@mute_logger('openerp.models')
def test_mail_message_access_create_doc(self):
# TODO Change the except_orm to Warning
Message = self.env['mail.message'].sudo(self.user_employee)
# Do: Raoul creates a message on Jobs -> ok, write access to the related document
self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_jobs_id, 'body': 'Test'})
Message.create({'model': 'mail.group', 'res_id': self.group_public.id, 'body': 'Test'})
# Do: Raoul creates a message on Priv -> ko, no write access to the related document
with self.assertRaises(AccessError):
self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test'})
# Do: Raoul creates a private message -> ok
self.mail_message.create(cr, user_raoul_id, {'body': 'Test'})
# Do: Raoul creates a reply to a message on Priv -> ko
with self.assertRaises(AccessError):
self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id})
# Do: Raoul creates a reply to a message on Priv-> ok if has received parent
self.mail_notification.create(cr, uid, {'message_id': priv_msg_id, 'partner_id': self.partner_raoul_id})
self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id})
with self.assertRaises(except_orm):
Message.create({'model': 'mail.group', 'res_id': self.group_private.id, 'body': 'Test'})
def test_20_message_set_star(self):
""" Tests for starring messages and its related access rights """
cr, uid = self.cr, self.uid
# Data: post a message on Pigs
def test_mail_message_access_create_private(self):
self.env['mail.message'].sudo(self.user_employee).create({'body': 'Test'})
def test_mail_message_access_create_reply(self):
self.env['mail.notification'].create({'message_id': self.message.id, 'partner_id': self.user_employee.partner_id.id})
self.env['mail.message'].sudo(self.user_employee).create({'model': 'mail.group', 'res_id': self.group_private.id, 'body': 'Test', 'parent_id': self.message.id})
def test_message_set_star(self):
msg_id = self.group_pigs.message_post(body='My Body', subject='1')
msg = self.mail_message.browse(cr, uid, msg_id)
msg_raoul = self.mail_message.browse(cr, self.user_raoul_id, msg_id)
msg = self.env['mail.message'].browse(msg_id)
msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg_id)
# Do: Admin stars msg
self.mail_message.set_message_starred(cr, uid, [msg.id], True)
msg.refresh()
# Test: notification exists
notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', self.partner_admin_id), ('message_id', '=', msg.id)])
self.assertEqual(len(notif_ids), 1, 'mail_message set_message_starred: more than one notification created')
# Test: notification starred
notif = self.mail_notification.browse(cr, uid, notif_ids[0])
self.assertTrue(notif.starred, 'mail_notification starred failed')
self.assertTrue(msg.starred, 'mail_message starred failed')
# Admin set as starred
msg.set_message_starred(True)
notification = self.env['mail.notification'].search([('partner_id', '=', self.env.user.partner_id.id), ('message_id', '=', msg.id)])
self.assertEqual(len(notification), 1)
self.assertTrue(notification.starred)
self.assertTrue(msg.starred)
# Do: Raoul stars msg
self.mail_message.set_message_starred(cr, self.user_raoul_id, [msg.id], True)
msg_raoul.refresh()
# Test: notification exists
notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', self.partner_raoul_id), ('message_id', '=', msg.id)])
self.assertEqual(len(notif_ids), 1, 'mail_message set_message_starred: more than one notification created')
# Test: notification starred
notif = self.mail_notification.browse(cr, uid, notif_ids[0])
self.assertTrue(notif.starred, 'mail_notification starred failed')
self.assertTrue(msg_raoul.starred, 'mail_message starred failed')
# Employee set as starred
msg_emp.set_message_starred(True)
notification = self.env['mail.notification'].search([('partner_id', '=', self.user_employee.partner_id.id), ('message_id', '=', msg.id)])
self.assertEqual(len(notification), 1)
self.assertTrue(notification.starred)
self.assertTrue(msg_emp.starred)
# Do: Admin unstars msg
self.mail_message.set_message_starred(cr, uid, [msg.id], False)
msg.refresh()
msg_raoul.refresh()
# Test: msg unstarred for Admin, starred for Raoul
self.assertFalse(msg.starred, 'mail_message starred failed')
self.assertTrue(msg_raoul.starred, 'mail_message starred failed')
msg.set_message_starred(False)
self.assertFalse(msg.starred)
self.assertTrue(msg_emp.starred)
def test_30_message_set_read(self):
""" Tests for reading messages and its related access rights """
cr, uid = self.cr, self.uid
# Data: post a message on Pigs
def test_message_set_read(self):
msg_id = self.group_pigs.message_post(body='My Body', subject='1')
msg = self.mail_message.browse(cr, uid, msg_id)
msg_raoul = self.mail_message.browse(cr, self.user_raoul_id, msg_id)
msg = self.env['mail.message'].browse(msg_id)
msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg_id)
# Do: Admin reads msg
self.mail_message.set_message_read(cr, uid, [msg.id], True)
msg.refresh()
# Test: notification exists
notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', self.partner_admin_id), ('message_id', '=', msg.id)])
self.assertEqual(len(notif_ids), 1, 'mail_message set_message_read: more than one notification created')
# Test: notification read
notif = self.mail_notification.browse(cr, uid, notif_ids[0])
self.assertTrue(notif['is_read'], 'mail_notification read failed')
self.assertFalse(msg.to_read, 'mail_message read failed')
# Admin set as read
msg.set_message_read(True)
notification = self.env['mail.notification'].search([('partner_id', '=', self.env.user.partner_id.id), ('message_id', '=', msg.id)])
self.assertEqual(len(notification), 1)
self.assertTrue(notification.is_read)
self.assertFalse(msg.to_read)
# Do: Raoul reads msg
self.mail_message.set_message_read(cr, self.user_raoul_id, [msg.id], True)
msg_raoul.refresh()
# Test: notification exists
notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', self.partner_raoul_id), ('message_id', '=', msg.id)])
self.assertEqual(len(notif_ids), 1, 'mail_message set_message_read: more than one notification created')
# Test: notification read
notif = self.mail_notification.browse(cr, uid, notif_ids[0])
self.assertTrue(notif['is_read'], 'mail_notification starred failed')
self.assertFalse(msg_raoul.to_read, 'mail_message starred failed')
# Employee set as read
msg_emp.set_message_read(True)
notification = self.env['mail.notification'].search([('partner_id', '=', self.user_employee.partner_id.id), ('message_id', '=', msg.id)])
self.assertEqual(len(notification), 1, 'mail_message set_message_read: more than one notification created')
self.assertTrue(notification.is_read)
self.assertFalse(msg_emp.to_read)
# Do: Admin unreads msg
self.mail_message.set_message_read(cr, uid, [msg.id], False)
msg.refresh()
msg_raoul.refresh()
# Test: msg unread for Admin, read for Raoul
self.assertTrue(msg.to_read, 'mail_message read failed')
self.assertFalse(msg_raoul.to_read, 'mail_message read failed')
msg.set_message_read(False)
self.assertTrue(msg.to_read)
self.assertFalse(msg_emp.to_read)
def test_40_message_vote(self):
""" Test designed for the vote/unvote feature. """
cr, uid = self.cr, self.uid
# Data: post a message on Pigs
def test_message_vote(self):
msg_id = self.group_pigs.message_post(body='My Body', subject='1')
msg = self.mail_message.browse(cr, uid, msg_id)
msg_raoul = self.mail_message.browse(cr, self.user_raoul_id, msg_id)
msg = self.env['mail.message'].browse(msg_id)
msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg_id)
# Do: Admin vote for msg
self.mail_message.vote_toggle(cr, uid, [msg.id])
msg.refresh()
# Test: msg has Admin as voter
self.assertEqual(set(msg.vote_user_ids), set([self.user_admin]), 'mail_message vote: after voting, Admin should be in the voter')
msg.vote_toggle()
self.assertEqual(msg.vote_user_ids, self.user_admin)
# Do: Bert vote for msg
self.mail_message.vote_toggle(cr, self.user_raoul_id, [msg.id])
msg_raoul.refresh()
msg_emp.vote_toggle()
# Test: msg has Admin and Bert as voters
self.assertEqual(set(msg_raoul.vote_user_ids), set([self.user_admin, self.user_raoul]), 'mail_message vote: after voting, Admin and Bert should be in the voters')
self.assertEqual(msg_emp.vote_user_ids, self.user_admin | self.user_employee)
# Do: Admin unvote for msg
self.mail_message.vote_toggle(cr, uid, [msg.id])
msg.refresh()
msg_raoul.refresh()
msg.vote_toggle()
# Test: msg has Bert as voter
self.assertEqual(set(msg.vote_user_ids), set([self.user_raoul]), 'mail_message vote: after unvoting, Bert should be in the voter')
self.assertEqual(set(msg_raoul.vote_user_ids), set([self.user_raoul]), 'mail_message vote: after unvoting, Bert should be in the voter')
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_50_mail_flow_access_rights(self):
""" Test a Chatter-looks alike flow to test access rights """
cr, uid = self.cr, self.uid
mail_compose = self.registry('mail.compose.message')
partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id
user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id
# Prepare groups: Pigs (employee), Jobs (public)
pigs_msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message', partner_ids=[self.partner_admin_id])
jobs_msg_id = self.mail_group.message_post(cr, uid, self.group_jobs_id, body='Message', partner_ids=[self.partner_admin_id])
# ----------------------------------------
# CASE1: Bert, without groups
# ----------------------------------------
# Do: Bert reads Jobs basic fields, ok because public = read access on the group
self.mail_group.read(cr, user_bert_id, [self.group_jobs_id], ['name', 'description'])
# Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages
jobs_message_ids = self.mail_group.read(cr, user_bert_id, [self.group_jobs_id], ['message_ids'])[0]['message_ids']
self.mail_message.read(cr, user_bert_id, jobs_message_ids)
# Do: Bert browses Jobs, ok (no direct browse of partners), ok for messages, ko for followers (accessible to employees or partner manager)
bert_jobs = self.mail_group.browse(cr, user_bert_id, self.group_jobs_id)
trigger_read = bert_jobs.name
for message in bert_jobs.message_ids:
trigger_read = message.subject
for partner in bert_jobs.message_follower_ids:
with self.assertRaises(AccessError):
trigger_read = partner.name
# Do: Bert comments Jobs, ko because no creation right
with self.assertRaises(AccessError):
self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs')
# Do: Bert writes on its own profile, ko because no message create access
with self.assertRaises(AccessError):
self.res_users.message_post(cr, user_bert_id, user_bert_id, body='I love Bert')
self.res_partner.message_post(cr, user_bert_id, partner_bert_id, body='I love Bert')
# ----------------------------------------
# CASE2: Raoul, employee
# ----------------------------------------
# Do: Raoul browses Jobs -> ok, ok for message_ids, of for message_follower_ids
raoul_jobs = self.mail_group.browse(cr, user_raoul_id, self.group_jobs_id)
trigger_read = raoul_jobs.name
for message in raoul_jobs.message_ids:
trigger_read = message.subject
for partner in raoul_jobs.message_follower_ids:
trigger_read = partner.name
# Do: Raoul comments Jobs, ok
self.mail_group.message_post(cr, user_raoul_id, self.group_jobs_id, body='I love Pigs')
# Do: Raoul create a mail.compose.message record on Jobs, because he uses the wizard
compose_id = mail_compose.create(cr, user_raoul_id,
{'subject': 'Subject', 'body': 'Body text', 'partner_ids': []},
{'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_jobs_id})
mail_compose.send_mail(cr, user_raoul_id, [compose_id])
# Do: Raoul replies to a Jobs message using the composer
compose_id = mail_compose.create(cr, user_raoul_id,
{'subject': 'Subject', 'body': 'Body text'},
{'default_composition_mode': 'comment', 'default_parent_id': pigs_msg_id})
mail_compose.send_mail(cr, user_raoul_id, [compose_id])
self.assertEqual(msg.vote_user_ids, self.user_employee)
self.assertEqual(msg_emp.vote_user_ids, self.user_employee)
+130
View File
@@ -0,0 +1,130 @@
# -*- coding: utf-8 -*-
import base64
from openerp.addons.mail.tests.common import TestMail
from openerp.tools import mute_logger
class TestMailTemplate(TestMail):
def setUp(self):
super(TestMailTemplate, self).setUp()
self._attachments = [{
'name': '_Test_First',
'datas_fname':
'first.txt',
'datas': base64.b64encode('My first attachment'),
'res_model': 'res.partner',
'res_id': self.user_admin.partner_id.id
}, {
'name': '_Test_Second',
'datas_fname': 'second.txt',
'datas': base64.b64encode('My second attachment'),
'res_model': 'res.partner',
'res_id': self.user_admin.partner_id.id
}]
self.email_1 = 'test1@example.com'
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'].search([('model', '=', 'mail.group')], limit=1).id,
'name': 'Pigs Template',
'subject': '${object.name}',
'body_html': '${object.description}',
'user_signature': False,
'attachment_ids': [(0, 0, self._attachments[0]), (0, 0, self._attachments[1])],
'partner_to': '%s,%s' % (self.partner_2.id, self.user_employee.partner_id.id),
'email_to': '%s, %s' % (self.email_1, self.email_2),
'email_cc': '%s' % self.email_3})
def test_composer_template_onchange(self):
composer = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'comment',
'default_model': 'mail.group',
'default_res_id': self.group_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.group', self.group_pigs.id)['value']
recipients = self.env['res.partner'].browse(values['partner_ids'])
attachments = self.env['ir.attachment'].browse(values['attachment_ids'])
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(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)
self.assertEqual(set(attachments.mapped('res_model')), set(['res.partner']))
self.assertEqual(set(attachments.mapped('res_id')), set([self.user_admin.partner_id.id]))
@mute_logger('openerp.addons.mail.mail_mail')
def test_composer_template_send(self):
composer = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'comment',
'default_model': 'mail.group',
'default_res_id': self.group_pigs.id,
'default_use_template': False,
'default_template_id': self.email_template.id,
}).create({}).send_mail()
message = self.group_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.partner_ids, test_recipients)
self.assertEqual(message.notified_partner_ids, test_recipients)
self.assertEqual(set(message.attachment_ids.mapped('res_model')), set(['mail.group']))
self.assertEqual(set(message.attachment_ids.mapped('res_id')), set([self.group_pigs.id]))
# self.assertIn((attach.datas_fname, base64.b64decode(attach.datas)), _attachments_test,
# 'mail.message attachment name / data incorrect')
@mute_logger('openerp.addons.mail.mail_mail')
def test_composer_template_mass_mailing(self):
composer = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'mass_mail',
'default_notify': True,
'default_model': 'mail.group',
'default_res_id': self.group_pigs.id,
'default_template_id': self.email_template.id,
'active_ids': [self.group_pigs.id, self.group_public.id]
}).create({})
values = composer.onchange_template_id(self.email_template.id, 'mass_mail', 'mail.group', self.group_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]
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')
# todo for JDC: ! (False -> <p>False</p>)
def test_mail_template(self):
mail_id = self.email_template.send_mail(self.group_pigs.id)
mail = self.env['mail.mail'].browse(mail_id)
self.assertEqual(mail.subject, self.group_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)
def test_message_compose_template_save(self):
self.env['mail.compose.message'].with_context(
{'default_composition_mode': 'comment',
'default_model': 'mail.group',
'default_res_id': self.group_pigs.id,
'active_ids': [self.group_pigs.id, self.group_public.id]
}).create({
'subject': 'Forget me subject',
'body': '<p>Dummy body</p>'
}).with_context({'default_model': 'mail.group'}).save_as_template()
# Test: email_template subject, body_html, model
last_template = self.env['mail.template'].search([('model', '=', 'mail.group'), ('subject', '=', 'Forget me subject')], limit=1)
self.assertEqual(last_template.body_html, '<p>Dummy body</p>', 'email_template incorrect body_html')
+85 -114
View File
@@ -1,85 +1,59 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.mail.tests.common import TestMail
from openerp.tools import mute_logger
class test_mail_access_rights(TestMail):
class TestMessageRead(TestMail):
def test_00_message_read(self):
""" Tests for message_read and expandables. """
cr, uid, user_admin, user_raoul, group_pigs = self.cr, self.uid, self.user_admin, self.user_raoul, self.group_pigs
self.mail_group.message_subscribe_users(cr, uid, [group_pigs.id], [user_raoul.id])
pigs_domain = [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)]
@mute_logger('openerp.addons.mail.mail_mail')
def setUp(self):
super(TestMessageRead, self).setUp()
self.group_pigs.message_subscribe_users([self.user_employee.id])
self.msg_id0 = self.group_pigs.message_post(body='0', subtype='mt_comment')
self.msg_id1 = self.group_pigs.message_post(body='1', subtype='mt_comment')
self.msg_id2 = self.group_pigs.message_post(body='2', subtype='mt_comment')
self.msg_id3 = self.group_pigs.message_post(body='1-1', subtype='mt_comment', parent_id=self.msg_id1)
self.msg_id4 = self.group_pigs.message_post(body='2-1', subtype='mt_comment', parent_id=self.msg_id2)
self.msg_id5 = self.group_pigs.message_post(body='1-2', subtype='mt_comment', parent_id=self.msg_id1)
self.msg_id6 = self.group_pigs.message_post(body='2-2', subtype='mt_comment', parent_id=self.msg_id2)
self.msg_id7 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=self.msg_id3)
self.msg_id8 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=self.msg_id4)
self.msg_id9 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=self.msg_id3)
self.msg_id10 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=self.msg_id4)
self.msg_ids = [self.msg_id10, self.msg_id9, self.msg_id8, self.msg_id7, self.msg_id6, self.msg_id5, self.msg_id4, self.msg_id3, self.msg_id2, self.msg_id1, self.msg_id0]
self.ordered_msg_ids = [self.msg_id2, self.msg_id4, self.msg_id6, self.msg_id8, self.msg_id10, self.msg_id1, self.msg_id3, self.msg_id5, self.msg_id7, self.msg_id9, self.msg_id0]
# Data: create a discussion in Pigs (3 threads, with respectively 0, 4 and 4 answers)
msg_id0 = self.group_pigs.message_post(body='0', subtype='mt_comment')
msg_id1 = self.group_pigs.message_post(body='1', subtype='mt_comment')
msg_id2 = self.group_pigs.message_post(body='2', subtype='mt_comment')
msg_id3 = self.group_pigs.message_post(body='1-1', subtype='mt_comment', parent_id=msg_id1)
msg_id4 = self.group_pigs.message_post(body='2-1', subtype='mt_comment', parent_id=msg_id2)
msg_id5 = self.group_pigs.message_post(body='1-2', subtype='mt_comment', parent_id=msg_id1)
msg_id6 = self.group_pigs.message_post(body='2-2', subtype='mt_comment', parent_id=msg_id2)
msg_id7 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=msg_id3)
msg_id8 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=msg_id4)
msg_id9 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=msg_id3)
msg_id10 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=msg_id4)
msg_ids = [msg_id10, msg_id9, msg_id8, msg_id7, msg_id6, msg_id5, msg_id4, msg_id3, msg_id2, msg_id1, msg_id0]
ordered_msg_ids = [msg_id2, msg_id4, msg_id6, msg_id8, msg_id10, msg_id1, msg_id3, msg_id5, msg_id7, msg_id9, msg_id0]
# TODO: with_context({'mail_read_set_read': True})
# Test: raoul received notifications
raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('is_read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)])
self.assertEqual(len(raoul_notification_ids), 11, 'message_post: wrong number of produced notifications')
def test_message_read_ids(self):
""" message_read: test reading specific ids """
messages = self.env['mail.message'].sudo(self.user_employee).message_read(self.msg_ids[2:4], domain=[('body', 'like', 'dummy')])
read_msg_ids = [msg.get('id') for msg in messages]
self.assertEqual(read_msg_ids, self.msg_ids[2:4], 'message_read with direct ids should read only the requested ids')
# Test: read some specific ids
read_msg_list = self.mail_message.message_read(cr, user_raoul.id, ids=msg_ids[2:4], domain=[('body', 'like', 'dummy')], context={'mail_read_set_read': True})
read_msg_ids = [msg.get('id') for msg in read_msg_list]
self.assertEqual(msg_ids[2:4], read_msg_ids, 'message_read with direct ids should read only the requested ids')
def test_message_read_domain(self):
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)], limit=200)
read_msg_ids = [msg.get('id') for msg in messages]
self.assertEqual(read_msg_ids, self.msg_ids, 'message_read flat with domain on Pigs should equal all messages of Pigs')
# Test: read messages of Pigs through a domain, being thread or not threaded
read_msg_list = self.mail_message.message_read(cr, user_raoul.id, domain=pigs_domain, limit=200)
read_msg_ids = [msg.get('id') for msg in read_msg_list]
self.assertEqual(msg_ids, read_msg_ids, 'message_read flat with domain on Pigs should equal all messages of Pigs')
read_msg_list = self.mail_message.message_read(cr, user_raoul.id, domain=pigs_domain, limit=200, thread_level=1)
read_msg_ids = [msg.get('id') for msg in read_msg_list]
self.assertEqual(ordered_msg_ids, read_msg_ids,
'message_read threaded with domain on Pigs should equal all messages of Pigs, and sort them with newer thread first, last message last in thread')
def test_message_read_domain_thread(self):
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)], limit=200, thread_level=1)
read_msg_ids = [msg.get('id') for msg in messages]
self.assertEqual(read_msg_ids, self.ordered_msg_ids, 'message_read threaded with domain on Pigs should equal all messages of Pigs, and sort them with newer thread first, last message last in thread')
# ----------------------------------------
# CASE1: message_read with domain, threaded
# We simulate an entire flow, using the expandables to test them
# ----------------------------------------
# Do: read last message, threaded
read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
def test_message_read_expandable(self):
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)], limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable']
# TDE TODO: test expandables order
type_list = map(lambda item: item.get('type'), read_msg_list)
type_list = map(lambda item: item.get('type'), messages)
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 4, 'message_read on last Pigs message should return 2 messages and 2 expandables')
self.assertEqual(set([msg_id2, msg_id10]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent')
self.assertEqual(read_msg_list[1].get('parent_id'), read_msg_list[0].get('id'), 'message_read should set the ancestor to the thread header')
self.assertEqual(len(messages), 4, 'message_read on last Pigs message should return 2 messages and 2 expandables')
self.assertEqual(set([self.msg_id2, self.msg_id10]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent')
self.assertEqual(messages[1].get('parent_id'), messages[0].get('id'), 'message_read should set the ancestor to the thread header')
# Data: get expandables
new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list:
for msg in messages:
if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'):
new_threads_exp = msg
elif msg.get('type') == 'expandable':
@@ -89,101 +63,98 @@ class test_mail_access_rights(TestMail):
self.assertIsNotNone(new_msg_exp, 'message_read on last Pigs message should have returned a new messages expandable')
domain = new_msg_exp.get('domain', [])
# Test: expandable, conditions in domain
self.assertIn(('id', 'child_of', msg_id2), domain, 'new messages expandable domain should contain a child_of condition')
self.assertIn(('id', '>=', msg_id4), domain, 'new messages expandable domain should contain an id greater than condition')
self.assertIn(('id', '<=', msg_id8), domain, 'new messages expandable domain should contain an id less than condition')
self.assertEqual(new_msg_exp.get('parent_id'), msg_id2, 'new messages expandable should have parent_id set to the thread header')
self.assertIn(('id', 'child_of', self.msg_id2), domain, 'new messages expandable domain should contain a child_of condition')
self.assertIn(('id', '>=', self.msg_id4), domain, 'new messages expandable domain should contain an id greater than condition')
self.assertIn(('id', '<=', self.msg_id8), domain, 'new messages expandable domain should contain an id less than condition')
self.assertEqual(new_msg_exp.get('parent_id'), self.msg_id2, 'new messages expandable should have parent_id set to the thread header')
# Do: message_read with domain, thread_level=0, parent_id=msg_id2 (should be imposed by JS), 2 messages
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=2, thread_level=0, parent_id=msg_id2)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
new_msg_exp = [msg for msg in read_msg_list if msg.get('type') == 'expandable'][0]
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=2, thread_level=0, parent_id=self.msg_id2)
read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable']
new_msg_exp = [msg for msg in messages if msg.get('type') == 'expandable'][0]
# Test: structure content, 2 messages and 1 thread expandable
self.assertEqual(len(read_msg_list), 3, 'message_read in Pigs thread should return 2 messages and 1 expandables')
self.assertEqual(set([msg_id6, msg_id8]), set(read_msg_ids), 'message_read in Pigs thread should return 2 more previous messages in thread')
self.assertEqual(len(messages), 3, 'message_read in Pigs thread should return 2 messages and 1 expandables')
self.assertEqual(set([self.msg_id6, self.msg_id8]), set(read_msg_ids), 'message_read in Pigs thread should return 2 more previous messages in thread')
# Do: read the last message
read_msg_list = self.mail_message.message_read(cr, uid, domain=new_msg_exp.get('domain'), limit=2, thread_level=0, parent_id=msg_id2)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=new_msg_exp.get('domain'), limit=2, thread_level=0, parent_id=self.msg_id2)
read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable']
# Test: structure content, 1 message
self.assertEqual(len(read_msg_list), 1, 'message_read in Pigs thread should return 1 message')
self.assertEqual(set([msg_id4]), set(read_msg_ids), 'message_read in Pigs thread should return the last message in thread')
self.assertEqual(len(messages), 1, 'message_read in Pigs thread should return 1 message')
self.assertEqual(set([self.msg_id4]), set(read_msg_ids), 'message_read in Pigs thread should return the last message in thread')
# Do: fetch a new thread, domain from expandable
self.assertIsNotNone(new_threads_exp, 'message_read on last Pigs message should have returned a new threads expandable')
domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain
for condition in pigs_domain:
for condition in [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)]:
self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter')
self.assertFalse(new_threads_exp.get('parent_id'), 'new threads expandable should not have an parent_id')
# Do: message_read with domain, thread_level=1 (should be imposed by JS)
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable']
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 4, 'message_read on Pigs should return 2 messages and 2 expandables')
self.assertEqual(set([msg_id1, msg_id9]), set(read_msg_ids), 'message_read on a Pigs message should also get its parent')
self.assertEqual(read_msg_list[1].get('parent_id'), read_msg_list[0].get('id'), 'message_read should set the ancestor to the thread header')
self.assertEqual(len(messages), 4, 'message_read on Pigs should return 2 messages and 2 expandables')
self.assertEqual(set([self.msg_id1, self.msg_id9]), set(read_msg_ids), 'message_read on a Pigs message should also get its parent')
self.assertEqual(messages[1].get('parent_id'), messages[0].get('id'), 'message_read should set the ancestor to the thread header')
# Data: get expandables
new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list:
for msg in messages:
if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'):
new_threads_exp = msg
elif msg.get('type') == 'expandable':
new_msg_exp = msg
# Do: fetch new messages in second thread, domain from expandable
self.assertIsNotNone(new_msg_exp, 'message_read on Pigs message should have returned a new messages expandable')
domain = new_msg_exp.get('domain', [])
# Test: expandable, conditions in domain
self.assertIn(('id', 'child_of', msg_id1), domain, 'new messages expandable domain should contain a child_of condition')
self.assertIn(('id', '>=', msg_id3), domain, 'new messages expandable domain should contain an id greater than condition')
self.assertIn(('id', '<=', msg_id7), domain, 'new messages expandable domain should contain an id less than condition')
self.assertEqual(new_msg_exp.get('parent_id'), msg_id1, 'new messages expandable should have ancestor_id set to the thread header')
self.assertIn(('id', 'child_of', self.msg_id1), domain, 'new messages expandable domain should contain a child_of condition')
self.assertIn(('id', '>=', self.msg_id3), domain, 'new messages expandable domain should contain an id greater than condition')
self.assertIn(('id', '<=', self.msg_id7), domain, 'new messages expandable domain should contain an id less than condition')
self.assertEqual(new_msg_exp.get('parent_id'), self.msg_id1, 'new messages expandable should have ancestor_id set to the thread header')
# Do: message_read with domain, thread_level=0, parent_id=msg_id1 (should be imposed by JS)
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=200, thread_level=0, parent_id=msg_id1)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=200, thread_level=0, parent_id=self.msg_id1)
read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable']
# Test: other message in thread have been fetch
self.assertEqual(set([msg_id3, msg_id5, msg_id7]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent')
self.assertEqual(set([self.msg_id3, self.msg_id5, self.msg_id7]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent')
# Test: fetch a new thread, domain from expandable
self.assertIsNotNone(new_threads_exp, 'message_read should have returned a new threads expandable')
domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain
for condition in pigs_domain:
for condition in [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)]:
self.assertIn(condition, domain, 'general expandable domain should contain the message_read domain parameter')
# Do: message_read with domain, thread_level=1 (should be imposed by JS)
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable']
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 1, 'message_read on Pigs should return 1 message because everything else has been fetched')
self.assertEqual([msg_id0], read_msg_ids, 'message_read after 2 More should return only 1 last message')
self.assertEqual(len(messages), 1, 'message_read on Pigs should return 1 message because everything else has been fetched')
self.assertEqual([self.msg_id0], read_msg_ids, 'message_read after 2 More should return only 1 last message')
# ----------------------------------------
# CASE2: message_read with domain, flat
# ----------------------------------------
# Do: read 2 lasts message, flat
read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=2, thread_level=0)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)], limit=2, thread_level=0)
read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable']
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is not set, 1 expandable
self.assertEqual(len(read_msg_list), 3, 'message_read on last Pigs message should return 2 messages and 1 expandable')
self.assertEqual(set([msg_id9, msg_id10]), set(read_msg_ids), 'message_read flat on Pigs last messages should only return those messages')
self.assertFalse(read_msg_list[0].get('parent_id'), 'message_read flat should set the ancestor as False')
self.assertFalse(read_msg_list[1].get('parent_id'), 'message_read flat should set the ancestor as False')
self.assertEqual(len(messages), 3, 'message_read on last Pigs message should return 2 messages and 1 expandable')
self.assertEqual(set([self.msg_id9, self.msg_id10]), set(read_msg_ids), 'message_read flat on Pigs last messages should only return those messages')
self.assertFalse(messages[0].get('parent_id'), 'message_read flat should set the ancestor as False')
self.assertFalse(messages[1].get('parent_id'), 'message_read flat should set the ancestor as False')
# Data: get expandables
new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list:
for msg in messages:
if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'):
new_threads_exp = msg
# Do: fetch new messages, domain from expandable
self.assertIsNotNone(new_threads_exp, 'message_read flat on the 2 last Pigs messages should have returns a new threads expandable')
domain = new_threads_exp.get('domain', [])
# Test: expandable, conditions in domain
for condition in pigs_domain:
for condition in [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)]:
self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter')
# Do: message_read with domain, thread_level=0 (should be imposed by JS)
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=20, thread_level=0)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=20, thread_level=0)
read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable']
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 9, 'message_read on Pigs should return 9 messages and 0 expandable')
self.assertEqual([msg_id8, msg_id7, msg_id6, msg_id5, msg_id4, msg_id3, msg_id2, msg_id1, msg_id0], read_msg_ids,
self.assertEqual(len(messages), 9, 'message_read on Pigs should return 9 messages and 0 expandable')
self.assertEqual([self.msg_id8, self.msg_id7, self.msg_id6, self.msg_id5, self.msg_id4, self.msg_id3, self.msg_id2, self.msg_id1, self.msg_id0], read_msg_ids,
'message_read, More on flat, should return all remaning messages')
+90
View File
@@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
from openerp.addons.mail.tests.common import TestMail
class TestTracking(TestMail):
def test_message_track(self):
""" Testing auto tracking of fields. Warning, it has not be cleaned and
should probably be. """
def _strip_string_spaces(body):
return body.replace(' ', '').replace('\n', '')
self.group_pigs.message_subscribe_users(user_ids=[self.user_employee.id])
# Data: res.users.group, to test group_public_id automatic logging
group_system_id = self.env['ir.model.data'].xmlid_to_res_id('base.group_system') or False
# Data: custom subtypes
Subtype = self.env['mail.message.subtype']
Data = self.env['ir.model.data']
mt_private = Subtype.create({'name': 'private', 'description': 'Private public'})
Data.create({'name': 'mt_private', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_private.id})
mt_name_supername = Subtype.create({'name': 'name_supername', 'description': 'Supername name'})
Data.create({'name': 'mt_name_supername', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_name_supername.id})
mt_group_public_set = Subtype.create({'name': 'group_public_set', 'description': 'Group set'})
Data.create({'name': 'mt_group_public_set', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_group_public_set.id})
mt_group_public = Subtype.create({'name': 'group_public', 'description': 'Group changed'})
Data.create({'name': 'mt_group_public', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_group_public.id})
def _track_subtype(self, cr, uid, ids, init_values, context=None):
record = self.browse(cr, uid, ids[0], context=context)
if 'public' in init_values and record.public == 'private':
return 'mail.mt_private'
elif 'name' in init_values and record.name == 'supername':
return 'mail.mt_name_supername'
elif 'group_public_id' in init_values and record.group_public_id:
return 'mail.mt_group_public_set'
elif 'group_public_id' in init_values and not record.group_public_id:
return 'mail.mt_group_public'
return False
self.registry('mail.group')._patch_method('_track_subtype', _track_subtype)
visibility = {'public': 'onchange', 'name': 'always', 'group_public_id': 'onchange'}
cls = type(self.env['mail.group'])
for key in visibility:
self.assertFalse(hasattr(getattr(cls, key), 'track_visibility'))
getattr(cls, key).track_visibility = visibility[key]
@self.addCleanup
def cleanup():
for key in visibility:
del getattr(cls, key).track_visibility
# Test: change name -> always tracked, not related to a subtype
self.group_pigs.sudo(self.user_employee).write({'public': 'public'})
self.assertEqual(len(self.group_pigs.message_ids.ids), 1, 'tracked: a message should have been produced')
# Test: first produced message: no subtype, name change tracked
last_msg = self.group_pigs.message_ids[-1]
self.assertFalse(last_msg.subtype_id.id, 'tracked: message should not have been linked to a subtype')
self.assertIn(u"Selectedgroupofusers\u2192Everyone", _strip_string_spaces(last_msg.body), 'tracked: message body incorrect')
self.assertIn('Pigs', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold always tracked field')
# Test: change name as supername, public as private -> 2 subtypes
self.group_pigs.sudo(self.user_employee).write({'name': 'supername', 'public': 'private'})
self.assertEqual(len(self.group_pigs.message_ids.ids), 2, 'tracked: two messages should have been produced')
# Test: first produced message: mt_name_supername
last_msg = self.group_pigs.message_ids[-2]
self.assertEqual(last_msg.subtype_id.id, mt_private.id, 'tracked: message should be linked to mt_private subtype')
self.assertIn('Private public', last_msg.body, 'tracked: message body does not hold the subtype description')
self.assertIn(u'Pigs\u2192supername', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect')
# Test: change public as public, group_public_id -> 1 subtype, name always tracked
self.group_pigs.sudo(self.user_employee).write({'public': 'public', 'group_public_id': group_system_id})
self.assertEqual(len(self.group_pigs.message_ids), 3, 'tracked: one message should have been produced')
# Test: first produced message: mt_group_public_set_id, with name always tracked, public tracked on change
last_msg = self.group_pigs.message_ids[-3]
self.assertEqual(last_msg.subtype_id, mt_group_public_set, 'tracked: message should be linked to mt_group_public_set_id')
self.assertIn('Group set', last_msg.body, 'tracked: message body does not hold the subtype description')
self.assertIn(u"Invitedpeopleonly\u2192Everyone", _strip_string_spaces(last_msg.body), 'tracked: message body does not hold changed tracked field')
self.assertIn(u'HumanResources/Employee\u2192Administration/Settings', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold always tracked field')
# Test: change group_public_id to False -> 1 subtype, name always tracked
self.group_pigs.sudo(self.user_employee).write({'group_public_id': False})
self.assertEqual(len(self.group_pigs.message_ids), 4, 'tracked: one message should have been produced')
# Test: first produced message: mt_group_public_set_id, with name always tracked, public tracked on change
last_msg = self.group_pigs.message_ids[-4]
self.assertEqual(last_msg.subtype_id, mt_group_public, 'tracked: message should be linked to mt_group_public_id')
self.assertIn('Group changed', last_msg.body, 'tracked: message body does not hold the subtype description')
self.assertIn(u'Administration/Settings\u2192', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold always tracked field')
# Test: change not tracked field, no tracking message
self.group_pigs.sudo(self.user_employee).write({'description': 'Dummy'})
self.assertEqual(len(self.group_pigs.message_ids), 4, 'tracked: No message should have been produced')
+1 -20
View File
@@ -1,22 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_portal
from . import test_portal
+61 -192
View File
@@ -1,228 +1,97 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.mail.tests.common import TestMail
from openerp.exceptions import AccessError
from openerp.tools.misc import mute_logger
class test_portal(TestMail):
def setUp(self):
super(test_portal, self).setUp()
cr, uid = self.cr, self.uid
def test_mail_compose_access_rights(self):
port_msg_id = self.group_portal.message_post(body='Message')
# Find Portal group
group_portal = self.registry('ir.model.data').get_object(cr, uid, 'base', 'group_portal')
self.group_portal_id = group_portal.id
# Create Chell (portal user)
self.user_chell_id = self.res_users.create(cr, uid, {'name': 'Chell Gladys', 'login': 'chell', 'email': 'chell@gladys.portal', 'groups_id': [(6, 0, [self.group_portal_id])]})
self.user_chell = self.res_users.browse(cr, uid, self.user_chell_id)
self.partner_chell_id = self.user_chell.partner_id.id
# Create a PigsPortal group
self.group_port_id = self.mail_group.create(cr, uid,
{'name': 'PigsPortal', 'public': 'groups', 'group_public_id': self.group_portal_id},
{'mail_create_nolog': True})
# Set an email address for the user running the tests, used as Sender for outgoing mails
self.res_users.write(cr, uid, uid, {'email': 'test@localhost'})
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_00_mail_access_rights(self):
""" Test basic mail_message and mail_group access rights for portal users. """
cr, uid = self.cr, self.uid
mail_compose = self.registry('mail.compose.message')
# Prepare group: Pigs and PigsPortal
pigs_msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message')
port_msg_id = self.mail_group.message_post(cr, uid, self.group_port_id, body='Message')
# Do: Chell browses Pigs -> ko, employee group
chell_pigs = self.mail_group.browse(cr, self.user_chell_id, self.group_pigs_id)
with self.assertRaises(AccessError):
trigger_read = chell_pigs.name
# Do: Chell posts a message on Pigs, crash because can not write on group or is not in the followers
with self.assertRaises(AccessError):
self.mail_group.message_post(cr, self.user_chell_id, self.group_pigs_id, body='Message')
# Do: Chell is added into Pigs followers and browse it -> ok for messages, ko for partners (no read permission)
self.mail_group.message_subscribe_users(cr, uid, [self.group_pigs_id], [self.user_chell_id])
chell_pigs = self.mail_group.browse(cr, self.user_chell_id, self.group_pigs_id)
trigger_read = chell_pigs.name
for message in chell_pigs.message_ids:
trigger_read = message.subject
for partner in chell_pigs.message_follower_ids:
if partner.id == self.partner_chell_id:
# Chell can read her own partner record
continue
with self.assertRaises(AccessError):
trigger_read = partner.name
# Do: Chell comments Pigs, ok because he is now in the followers
self.mail_group.message_post(cr, self.user_chell_id, self.group_pigs_id, body='I love Pigs')
# Do: Chell comments Pigs, ok because can write on it (public group)
self.group_portal.sudo(self.user_portal).message_post(body='I love Pigs')
# Do: Chell creates a mail.compose.message record on Pigs, because he uses the wizard
compose_id = mail_compose.create(cr, self.user_chell_id,
{'subject': 'Subject', 'body': 'Body text', 'partner_ids': []},
{'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id})
mail_compose.send_mail(cr, self.user_chell_id, [compose_id])
compose = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'comment',
'default_model': 'mail.group',
'default_res_id': self.group_portal.id
}).sudo(self.user_portal).create({
'subject': 'Subject',
'body': 'Body text',
'partner_ids': []})
compose.send_mail()
# Do: Chell replies to a Pigs message using the composer
compose_id = mail_compose.create(cr, self.user_chell_id,
{'subject': 'Subject', 'body': 'Body text'},
{'default_composition_mode': 'comment', 'default_parent_id': pigs_msg_id})
mail_compose.send_mail(cr, self.user_chell_id, [compose_id])
compose = self.env['mail.compose.message'].with_context({
'default_composition_mode': 'comment',
'default_parent_id': port_msg_id
}).sudo(self.user_portal).create({
'subject': 'Subject',
'body': 'Body text'})
compose.send_mail()
# Do: Chell browses PigsPortal -> ok because groups security, ko for partners (no read permission)
chell_port = self.mail_group.browse(cr, self.user_chell_id, self.group_port_id)
trigger_read = chell_port.name
for message in chell_port.message_ids:
trigger_read = message.subject
for partner in chell_port.message_follower_ids:
with self.assertRaises(AccessError):
trigger_read = partner.name
def test_10_mail_invite(self):
cr, uid = self.cr, self.uid
mail_invite = self.registry('mail.wizard.invite')
base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='')
@mute_logger('openerp.addons.mail.mail_mail')
def test_invite_email_portal(self):
group_pigs = self.group_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_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c'})
partner_carine = self.env['res.partner'].create({'name': 'Carine Poilvache', 'email': 'c@c'})
# Do: create a mail_wizard_invite, validate it
self._init_mock_build_email()
context = {'default_res_model': 'mail.group', 'default_res_id': self.group_pigs_id}
mail_invite_id = mail_invite.create(cr, uid, {'partner_ids': [(4, partner_carine_id)], 'send_mail': True}, context)
mail_invite.add_followers(cr, uid, [mail_invite_id])
mail_invite = self.env['mail.wizard.invite'].with_context({
'default_res_model': 'mail.group',
'default_res_id': group_pigs.id}).create({
'partner_ids': [(4, partner_carine.id)], 'send_mail': True})
mail_invite.add_followers()
# Test: Pigs followers should contain Admin and Bert
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
self.assertEqual(set(follower_ids), set([self.partner_admin_id, partner_carine_id]), 'Pigs followers after invite is incorrect')
self.assertEqual(group_pigs.message_follower_ids, partner_carine)
# Test: partner must have been prepared for signup
partner_carine = self.res_partner.browse(cr, uid, partner_carine_id)
self.assertTrue(partner_carine.signup_valid, 'partner has not been prepared for signup')
self.assertTrue(base_url in partner_carine.signup_url, 'signup url is incorrect')
self.assertTrue(cr.dbname in partner_carine.signup_url, 'signup url is incorrect')
self.assertTrue(self.env.cr.dbname in partner_carine.signup_url, 'signup url is incorrect')
self.assertTrue(partner_carine.signup_token in partner_carine.signup_url, 'signup url is incorrect')
# Test: (pretend to) send email and check subject, body
self.assertEqual(len(self._build_email_kwargs_list), 1, 'sent email number incorrect, should be only for Bert')
for sent_email in self._build_email_kwargs_list:
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Discussion group: Pigs',
'invite: subject of invitation email is incorrect')
self.assertIn('Administrator invited you to follow Discussion group document: Pigs', sent_email.get('body'),
'invite: body of invitation email is incorrect')
self.assertIn(partner_carine.signup_token, sent_email.get('body'),
'invite: body of invitation email does not contain signup token')
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 group: Pigs',
'invite: subject of invitation email is incorrect')
self.assertIn(
'Administrator invited you to follow Discussion group document: Pigs', sent_email.get('body'),
'invite: body of invitation email is incorrect')
self.assertIn(
partner_carine.signup_token, sent_email.get('body'),
'invite: body of invitation email does not contain signup token')
def test_20_notification_url(self):
""" Tests designed to test the URL added in notification emails. """
cr, uid, group_pigs = self.cr, self.uid, self.group_pigs
# Partner data
partner_raoul = self.res_partner.browse(cr, uid, self.partner_raoul_id)
partner_bert_id = self.res_partner.create(cr, uid, {'name': 'bert'})
partner_bert = self.res_partner.browse(cr, uid, partner_bert_id)
def test_mail_notification_url_partner_portal(self):
# Mail data
mail_mail_id = self.mail_mail.create(cr, uid, {'state': 'exception'})
mail = self.mail_mail.browse(cr, uid, mail_mail_id)
mail = self.env['mail.mail'].create({'state': 'exception'})
# Test: link for nobody -> None
url = self.mail_mail._get_partner_access_link(cr, uid, mail)
url = self.env['mail.mail']._get_partner_access_link(mail)
self.assertEqual(url, None,
'notification email: mails not send to a specific partner should not have any URL')
'notification email: mails not send to a specific partner should not have any URL')
# Test: link for partner -> signup URL
url = self.mail_mail._get_partner_access_link(cr, uid, mail, partner=partner_bert)
self.assertIn(partner_bert.signup_token, url,
'notification email: mails send to a not-user partner should contain the signup token')
url = self.env['mail.mail']._get_partner_access_link(mail, partner=self.partner_1)
self.assertIn(self.partner_1.signup_token, url,
'notification email: mails send to a not-user partner should contain the signup token')
# Test: link for user -> signin
url = self.mail_mail._get_partner_access_link(cr, uid, mail, partner=partner_raoul)
url = self.env['mail.mail']._get_partner_access_link(mail, partner=self.user_employee.partner_id)
self.assertIn('action=mail.action_mail_redirect', url,
'notification email: link should contain the redirect action')
self.assertIn('login=%s' % partner_raoul.user_ids[0].login, url,
'notification email: link should contain the user login')
'notification email: link should contain the redirect action')
self.assertIn('login=%s' % self.user_employee.login, url,
'notification email: link should contain the user login')
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.models')
def test_21_inbox_redirection(self):
""" Tests designed to test the inbox redirection of emails notification URLs. """
cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs
model, act_id = self.ir_model_data.get_object_reference(cr, uid, 'mail', 'action_mail_inbox_feeds')
model, port_act_id = self.ir_model_data.get_object_reference(cr, uid, 'portal', 'action_mail_inbox_feeds_portal')
@mute_logger('openerp.addons.mail.mail_mail', 'openerp.models')
def test_inbox_redirection_portal(self):
group_pigs = self.group_pigs
port_act_id = self.ref('portal.action_mail_inbox_feeds_portal')
# Data: post a message on pigs
msg_id = self.group_pigs.message_post(body='My body', partner_ids=[self.partner_bert_id, self.partner_chell_id], type='comment', subtype='mail.mt_comment')
# No specific parameters -> should redirect to Inbox
action = self.mail_thread.message_redirect_action(cr, self.user_raoul_id, {'params': {}})
self.assertEqual(action.get('type'), 'ir.actions.client',
'URL redirection: action without parameters should redirect to client action Inbox')
self.assertEqual(action.get('id'), act_id,
'URL redirection: action without parameters should redirect to client action Inbox')
# Bert has read access to Pigs -> should redirect to form view of Pigs
action = self.mail_thread.message_redirect_action(cr, self.user_raoul_id, {'params': {'message_id': msg_id}})
self.assertEqual(action.get('type'), 'ir.actions.act_window',
'URL redirection: action with message_id for read-accredited user should redirect to Pigs')
self.assertEqual(action.get('res_id'), group_pigs.id,
'URL redirection: action with message_id for read-accredited user should redirect to Pigs')
# Bert has no read access to Pigs -> should redirect to Inbox
action = self.mail_thread.message_redirect_action(cr, self.user_bert_id, {'params': {'message_id': msg_id}})
self.assertEqual(action.get('type'), 'ir.actions.client',
'URL redirection: action without parameters should redirect to client action Inbox')
self.assertEqual(action.get('id'), act_id,
'URL redirection: action without parameters should redirect to client action Inbox')
msg_id = group_pigs.message_post(body='My body', partner_ids=[self.user_employee.partner_id.id, self.user_portal.partner_id.id], type='comment', subtype='mail.mt_comment')
# Chell has no read access to pigs -> should redirect to Portal Inbox
action = self.mail_thread.message_redirect_action(cr, self.user_chell_id, {'params': {'message_id': msg_id}})
action = self.env['mail.thread'].with_context({'params': {'message_id': msg_id}}).sudo(self.user_portal).message_redirect_action()
self.assertEqual(action.get('type'), 'ir.actions.client',
'URL redirection: action without parameters should redirect to client action Inbox')
self.assertEqual(action.get('id'), port_act_id,
'URL redirection: action without parameters should redirect to client action Inbox')
def test_30_message_read(self):
cr, uid, group_port_id = self.cr, self.uid, self.group_port_id
# Data: custom subtypes
mt_group_public_id = self.mail_message_subtype.create(cr, uid, {'name': 'group_public', 'description': 'Group changed'})
self.ir_model_data.create(cr, uid, {'name': 'mt_group_public', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_group_public_id})
# Data: post messages with various subtypes
msg1_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body1', type='comment', subtype='mail.mt_comment')
msg2_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body2', type='comment', subtype='mail.mt_group_public')
msg3_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body3', type='comment', subtype='mail.mt_comment')
msg4_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body4', type='comment')
# msg5_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body5', type='notification')
# Do: Chell search messages: should not see internal notes (comment without subtype)
msg_ids = self.mail_message.search(cr, self.user_chell_id, [('model', '=', 'mail.group'), ('res_id', '=', group_port_id)])
self.assertEqual(set(msg_ids), set([msg1_id, msg2_id, msg3_id]),
'mail_message: portal user has access to messages he should not read')
# Do: Chell read messages she can read
self.mail_message.read(cr, self.user_chell_id, msg_ids, ['body', 'type', 'subtype_id'])
# Do: Chell read a message she should not be able to read
with self.assertRaises(AccessError):
self.mail_message.read(cr, self.user_chell_id, [msg4_id], ['body', 'type', 'subtype_id'])
+111 -160
View File
@@ -29,234 +29,185 @@ class TestPortalProjectBase(TestProjectBase):
def setUp(self):
super(TestPortalProjectBase, self).setUp()
cr, uid = self.cr, self.uid
# Find Portal group
group_portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_portal')
self.group_portal_id = group_portal_ref and group_portal_ref[1] or False
# Find Public group
group_public_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_public')
self.group_public_id = group_public_ref and group_public_ref[1] or False
# # Test users to use through the various tests
self.user_portal_id = self.res_users.create(cr, uid, {
'name': 'Chell Portal',
'login': 'chell',
'alias_name': 'chell',
'groups_id': [(6, 0, [self.group_portal_id])]
})
self.user_public_id = self.res_users.create(cr, uid, {
'name': 'Donovan Public',
'login': 'donovan',
'alias_name': 'donovan',
'groups_id': [(6, 0, [self.group_public_id])]
})
self.user_manager_id = self.res_users.create(cr, uid, {
'name': 'Eustache Manager',
'login': 'eustache',
'alias_name': 'eustache',
'groups_id': [(6, 0, [self.group_project_manager_id])]
})
# Test 'Pigs' project
self.project_pigs_id = self.project_project.create(cr, uid, {
'name': 'Pigs', 'privacy_visibility': 'public'}, {'mail_create_nolog': True})
# Various test tasks
self.task_1_id = self.project_task.create(cr, uid, {
'name': 'Test1', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.task_2_id = self.project_task.create(cr, uid, {
'name': 'Test2', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.task_3_id = self.project_task.create(cr, uid, {
'name': 'Test3', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.task_4_id = self.project_task.create(cr, uid, {
'name': 'Test4', 'user_id': self.user_projectuser_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.task_5_id = self.project_task.create(cr, uid, {
'name': 'Test5', 'user_id': self.user_portal_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.task_6_id = self.project_task.create(cr, uid, {
'name': 'Test6', 'user_id': self.user_public_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.task_3 = self.env['project.task'].with_context({'mail_create_nolog': True}).create({
'name': 'Test3', 'user_id': self.user_portal.id, 'project_id': self.project_pigs.id})
self.task_4 = self.env['project.task'].with_context({'mail_create_nolog': True}).create({
'name': 'Test4', 'user_id': self.user_public.id, 'project_id': self.project_pigs.id})
self.task_5 = self.env['project.task'].with_context({'mail_create_nolog': True}).create({
'name': 'Test5', 'user_id': False, 'project_id': self.project_pigs.id})
self.task_6 = self.env['project.task'].with_context({'mail_create_nolog': True}).create({
'name': 'Test5', 'user_id': False, 'project_id': self.project_pigs.id})
class TestPortalProject(TestPortalProjectBase):
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_00_project_access_rights(self):
""" Test basic project access rights, for project and portal_project """
cr, uid, pigs_id = self.cr, self.uid, self.project_pigs_id
# ----------------------------------------
# CASE1: public project
# ----------------------------------------
@mute_logger('openerp.addons.base.ir.ir_model')
def test_public_project_access_rights(self):
pigs = self.project_pigs
# Do: Alfred reads project -> ok (employee ok public)
self.project_project.read(cr, self.user_projectuser_id, [pigs_id], ['state'])
pigs.sudo(self.user_projectuser.id).read(['state'])
# Test: all project tasks visible
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
test_task_ids = set([self.task_1_id, self.task_2_id, self.task_3_id, self.task_4_id, self.task_5_id, self.task_6_id])
self.assertEqual(set(task_ids), test_task_ids,
'access rights: project user cannot see all tasks of a public project')
tasks = self.env['project.task'].sudo(self.user_projectuser.id).search([('project_id', '=', pigs.id)])
self.assertEqual(tasks, self.task_1 | self.task_2 | self.task_3 | self.task_4 | self.task_5 | self.task_6,
'access rights: project user should see all tasks of public project')
# Test: all project tasks readable
self.project_task.read(cr, self.user_projectuser_id, task_ids, ['name'])
tasks.read(['name'])
# Test: all project tasks writable
self.project_task.write(cr, self.user_projectuser_id, task_ids, {'description': 'TestDescription'})
tasks.write({'description': 'TestDescription'})
# Need to check assertRaises
# Do: Bert reads project -> crash, no group
self.assertRaises(AccessError, self.project_project.read, cr, self.user_none_id, [pigs_id], ['state'])
self.assertRaises(AccessError, pigs.sudo(self.user_noone).read, ['state'])
# Test: no project task visible
self.assertRaises(AccessError, self.project_task.search, cr, self.user_none_id, [('project_id', '=', pigs_id)])
self.assertRaises(AccessError, self.env['project.task'].sudo(self.user_noone).search, [('project_id', '=', pigs.id)])
# Test: no project task readable
self.assertRaises(AccessError, self.project_task.read, cr, self.user_none_id, task_ids, ['name'])
self.assertRaises(AccessError, tasks.sudo(self.user_noone).read, ['name'])
# Test: no project task writable
self.assertRaises(AccessError, self.project_task.write, cr, self.user_none_id, task_ids, {'description': 'TestDescription'})
self.assertRaises(AccessError, tasks.sudo(self.user_noone).write, {'description': 'TestDescription'})
# Do: Chell reads project -> ok (portal ok public)
self.project_project.read(cr, self.user_portal_id, [pigs_id], ['state'])
pigs.sudo(self.user_portal).read(['state'])
# Test: all project tasks visible
task_ids = self.project_task.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
self.assertEqual(set(task_ids), test_task_ids,
'access rights: project user cannot see all tasks of a public project')
tasks = self.env['project.task'].sudo(self.user_portal).search([('project_id', '=', pigs.id)])
self.assertEqual(tasks, self.task_1 | self.task_2 | self.task_3 | self.task_4 | self.task_5 | self.task_6,
'access rights: portal user should see all tasks of a public project')
# Test: all project tasks readable
self.project_task.read(cr, self.user_portal_id, task_ids, ['name'])
tasks.read(['name'])
# Test: no project task writable
self.assertRaises(AccessError, self.project_task.write, cr, self.user_portal_id, task_ids, {'description': 'TestDescription'})
self.assertRaises(AccessError, tasks.write, {'description': 'TestDescription'})
# Do: Donovan reads project -> ok (public)
self.project_project.read(cr, self.user_public_id, [pigs_id], ['state'])
pigs.sudo(self.user_public).read(['state'])
# Test: all project tasks visible
task_ids = self.project_task.search(cr, self.user_public_id, [('project_id', '=', pigs_id)])
self.assertEqual(set(task_ids), test_task_ids,
'access rights: public user cannot see all tasks of a public project')
tasks = self.env['project.task'].sudo(self.user_public.id).search([('project_id', '=', pigs.id)])
self.assertEqual(tasks, self.task_1 | self.task_2 | self.task_3 | self.task_4 | self.task_5 | self.task_6,
'access rights: public user should see all tasks of a public project')
# Test: all project tasks readable
self.project_task.read(cr, self.user_public_id, task_ids, ['name'])
tasks.read(['name'])
# Test: no project task writable
self.assertRaises(AccessError, self.project_task.write, cr, self.user_public_id, task_ids, {'description': 'TestDescription'})
self.assertRaises(AccessError, tasks.write, {'description': 'TestDescription'})
# ----------------------------------------
# CASE2: portal project
# ----------------------------------------
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'portal'})
self.project_project.invalidate_cache(cr, uid)
@mute_logger('openerp.addons.base.ir.ir_model')
def test_portal_project_access_rights(self):
pigs = self.project_pigs
pigs.write({'privacy_visibility': 'portal'})
# Do: Alfred reads project -> ok (employee ok public)
self.project_project.read(cr, self.user_projectuser_id, [pigs_id], ['state'])
pigs.sudo(self.user_projectuser).read(['state'])
# Test: all project tasks visible
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
self.assertEqual(set(task_ids), test_task_ids,
'access rights: project user cannot see all tasks of a portal project')
tasks = self.env['project.task'].sudo(self.user_projectuser).search([('project_id', '=', pigs.id)])
self.assertEqual(tasks, self.task_1 | self.task_2 | self.task_3 | self.task_4 | self.task_5 | self.task_6,
'access rights: project user should see all tasks of a portal project')
# Do: Bert reads project -> crash, no group
self.assertRaises(AccessError, self.project_project.read, cr, self.user_none_id, [pigs_id], ['state'])
self.assertRaises(AccessError, pigs.sudo(self.user_noone).read, ['state'])
# Test: no project task searchable
self.assertRaises(AccessError, self.project_task.search, cr, self.user_none_id, [('project_id', '=', pigs_id)])
self.assertRaises(AccessError, self.env['project.task'].sudo(self.user_noone).search, [('project_id', '=', pigs.id)])
# Data: task follower
self.project_project.message_subscribe_users(cr, self.user_manager_id, [pigs_id], [self.user_portal_id])
self.project_task.message_subscribe_users(cr, self.user_projectuser_id, [self.task_1_id, self.task_3_id], [self.user_portal_id])
# Do: Chell reads project -> ok (portal ok portal)
self.project_project.read(cr, self.user_portal_id, [pigs_id], ['state'])
pigs.sudo(self.user_projectmanager).message_subscribe_users(user_ids=[self.user_portal.id])
self.task_1.sudo(self.user_projectuser).message_subscribe_users(user_ids=[self.user_portal.id])
self.task_3.sudo(self.user_projectuser).message_subscribe_users(user_ids=[self.user_portal.id])
# Do: Chell reads project -> ok (portal ok public)
pigs.sudo(self.user_portal).read(['state'])
# Do: Donovan reads project -> ko (public ko portal)
self.assertRaises(AccessError, self.project_project.read, cr, self.user_public_id, [pigs_id], ['state'])
# TODO: Change the except_orm to Warning ( Because here it's call check_access_rule
# which still generate exception in except_orm.)
self.assertRaises(except_orm, pigs.sudo(self.user_public).read, ['state'])
# Test: no project task visible
task_ids = self.project_task.search(cr, self.user_public_id, [('project_id', '=', pigs_id)])
self.assertFalse(task_ids, 'access rights: public user should not see tasks of a portal project')
tasks = self.env['project.task'].sudo(self.user_public).search([('project_id', '=', pigs.id)])
self.assertFalse(tasks, 'access rights: public user should not see tasks of a portal project')
# Data: task follower cleaning
self.project_task.message_unsubscribe_users(cr, self.user_projectuser_id, [self.task_1_id, self.task_3_id], [self.user_portal_id])
self.task_1.sudo(self.user_projectuser).message_unsubscribe_users(user_ids=[self.user_portal.id])
self.task_3.sudo(self.user_projectuser).message_unsubscribe_users(user_ids=[self.user_portal.id])
# ----------------------------------------
# CASE3: employee project
# ----------------------------------------
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'employees'})
self.project_project.invalidate_cache(cr, uid)
@mute_logger('openerp.addons.base.ir.ir_model')
def test_employee_project_access_rights(self):
pigs = self.project_pigs
pigs.write({'privacy_visibility': 'employees'})
# Do: Alfred reads project -> ok (employee ok employee)
self.project_project.read(cr, self.user_projectuser_id, [pigs_id], ['state'])
pigs.sudo(self.user_projectuser).read(['state'])
# Test: all project tasks visible
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
test_task_ids = set([self.task_1_id, self.task_2_id, self.task_3_id, self.task_4_id, self.task_5_id, self.task_6_id])
self.assertEqual(set(task_ids), test_task_ids,
'access rights: project user cannot see all tasks of an employees project')
tasks = self.env['project.task'].sudo(self.user_projectuser).search([('project_id', '=', pigs.id)])
test_task_ids = set([self.task_1.id, self.task_2.id, self.task_3.id, self.task_4.id, self.task_5.id, self.task_6.id])
self.assertEqual(set(tasks.ids), test_task_ids,
'access rights: project user cannot see all tasks of an employees project')
# Do: Bert reads project -> crash, no group
self.assertRaises(AccessError, self.project_project.read, cr, self.user_none_id, [pigs_id], ['state'])
self.assertRaises(AccessError, pigs.sudo(self.user_noone).read, ['state'])
# Do: Chell reads project -> ko (portal ko employee)
self.assertRaises(AccessError, self.project_project.read, cr, self.user_portal_id, [pigs_id], ['state'])
# TODO Change the except_orm to Warning
self.assertRaises(except_orm, pigs.sudo(self.user_portal).read, ['state'])
# Test: no project task visible + assigned
task_ids = self.project_task.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
self.assertFalse(task_ids, 'access rights: portal user should not see tasks of an employees project, even if assigned')
tasks = self.env['project.task'].sudo(self.user_portal).search([('project_id', '=', pigs.id)])
self.assertFalse(tasks.ids, 'access rights: portal user should not see tasks of an employees project, even if assigned')
# Do: Donovan reads project -> ko (public ko employee)
self.assertRaises(AccessError, self.project_project.read, cr, self.user_public_id, [pigs_id], ['state'])
# TODO Change the except_orm to Warning
self.assertRaises(except_orm, pigs.sudo(self.user_public).read, ['state'])
# Test: no project task visible
task_ids = self.project_task.search(cr, self.user_public_id, [('project_id', '=', pigs_id)])
self.assertFalse(task_ids, 'access rights: public user should not see tasks of an employees project')
tasks = self.env['project.task'].sudo(self.user_public).search([('project_id', '=', pigs.id)])
self.assertFalse(tasks.ids, 'access rights: public user should not see tasks of an employees project')
# Do: project user is employee and can create a task
tmp_task_id = self.project_task.create(cr, self.user_projectuser_id, {
'name': 'Pigs task', 'project_id': pigs_id
}, {'mail_create_nolog': True})
self.project_task.unlink(cr, self.user_projectuser_id, [tmp_task_id])
tmp_task = self.env['project.task'].sudo(self.user_projectuser).with_context({'mail_create_nolog': True}).create({
'name': 'Pigs task',
'project_id': pigs.id})
tmp_task.sudo(self.user_projectuser).unlink()
# ----------------------------------------
# CASE4: followers project
# ----------------------------------------
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'followers'})
self.project_project.invalidate_cache(cr, uid)
@mute_logger('openerp.addons.base.ir.ir_model')
def test_followers_project_access_rights(self):
pigs = self.project_pigs
pigs.write({'privacy_visibility': 'followers'})
# Do: Alfred reads project -> ko (employee ko followers)
self.assertRaises(AccessError, self.project_project.read, cr, self.user_projectuser_id, [pigs_id], ['state'])
# TODO Change the except_orm to Warning
self.assertRaises(AccessError, pigs.sudo(self.user_projectuser).read, ['state'])
# Test: no project task visible
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
test_task_ids = set([self.task_4_id])
self.assertEqual(set(task_ids), test_task_ids,
tasks = self.env['project.task'].sudo(self.user_projectuser).search([('project_id', '=', pigs.id)])
self.assertEqual(tasks, self.task_1,
'access rights: employee user should not see tasks of a not-followed followers project, only assigned')
# Do: Bert reads project -> crash, no group
self.assertRaises(AccessError, self.project_project.read, cr, self.user_none_id, [pigs_id], ['state'])
# Do: Chell reads project -> ko (portal ko followers)
self.project_project.message_unsubscribe_users(cr, self.user_portal_id, [pigs_id], [self.user_portal_id])
self.assertRaises(except_orm, self.project_project.read, cr, self.user_portal_id, [pigs_id], ['state'])
self.assertRaises(AccessError, pigs.sudo(self.user_noone).read, ['state'])
# Do: Chell reads project -> ko (portal ko employee)
self.assertRaises(except_orm, pigs.sudo(self.user_portal).read, ['state'])
# Test: no project task visible
task_ids = self.project_task.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
test_task_ids = set([self.task_5_id])
self.assertEqual(set(task_ids), test_task_ids,
tasks = self.env['project.task'].sudo(self.user_portal).search([('project_id', '=', pigs.id)])
self.assertEqual(tasks, self.task_3,
'access rights: portal user should not see tasks of a not-followed followers project, only assigned')
# Do: Donovan reads project -> ko (public ko employee)
self.assertRaises(AccessError, self.project_project.read, cr, self.user_public_id, [pigs_id], ['state'])
# TODO Change the except_orm to Warning
self.assertRaises(except_orm, pigs.sudo(self.user_public).read, ['state'])
# Test: no project task visible
task_ids = self.project_task.search(cr, self.user_public_id, [('project_id', '=', pigs_id)])
self.assertFalse(task_ids, 'access rights: public user should not see tasks of a followers project')
tasks = self.env['project.task'].sudo(self.user_public).search([('project_id', '=', pigs.id)])
self.assertFalse(tasks, 'access rights: public user should not see tasks of a followers project')
# Data: subscribe Alfred, Chell and Donovan as follower
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_projectuser_id, self.user_portal_id, self.user_public_id])
self.project_task.message_subscribe_users(cr, self.user_manager_id, [self.task_1_id, self.task_3_id], [self.user_portal_id, self.user_projectuser_id])
pigs.message_subscribe_users(user_ids=[self.user_projectuser.id, self.user_portal.id, self.user_public.id])
self.task_1.sudo(self.user_projectmanager).message_subscribe_users(user_ids=[self.user_portal.id, self.user_projectuser.id])
self.task_3.sudo(self.user_projectmanager).message_subscribe_users(user_ids=[self.user_portal.id, self.user_projectuser.id])
# Do: Alfred reads project -> ok (follower ok followers)
self.project_project.read(cr, self.user_projectuser_id, [pigs_id], ['state'])
pigs.sudo(self.user_projectuser).read(['state'])
# Do: Chell reads project -> ok (follower ok follower)
self.project_project.read(cr, self.user_portal_id, [pigs_id], ['state'])
pigs.sudo(self.user_portal).read(['state'])
# Do: Donovan reads project -> ko (public ko follower even if follower)
self.assertRaises(except_orm, self.project_project.read, cr, self.user_public_id, [pigs_id], ['state'])
# TODO Change the except_orm to Warning
self.assertRaises(except_orm, pigs.sudo(self.user_public).read, ['state'])
# Do: project user is follower of the project and can create a task
self.project_task.create(cr, self.user_projectuser_id, {
'name': 'Pigs task', 'project_id': pigs_id
}, {'mail_create_nolog': True})
self.env['project.task'].sudo(self.user_projectuser.id).with_context({'mail_create_nolog': True}).create({
'name': 'Pigs task', 'project_id': pigs.id
})
# not follower user should not be able to create a task
self.project_project.message_unsubscribe_users(cr, self.user_projectuser_id, [pigs_id], [self.user_projectuser_id])
self.assertRaises(except_orm,
self.project_task.create, cr, self.user_projectuser_id, {'name': 'Pigs task', 'project_id': pigs_id}, {'mail_create_nolog': True}
)
pigs.sudo(self.user_projectuser).message_unsubscribe_users(user_ids=[self.user_projectuser.id])
self.assertRaises(except_orm, self.env['project.task'].sudo(self.user_projectuser).with_context({
'mail_create_nolog': True}).create, {'name': 'Pigs task', 'project_id': pigs.id})
# Do: project user can create a task without project
self.project_task.create(cr, self.user_projectuser_id, {'name': 'Pigs task', 'project_id': False}, {'mail_create_nolog': True})
self.assertRaises(except_orm, self.env['project.task'].sudo(self.user_projectuser).with_context({
'mail_create_nolog': True}).create, {'name': 'Pigs task', 'project_id': pigs.id})
+1 -21
View File
@@ -1,23 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_project_flow
from . import test_project_base, test_project_flow
+16 -70
View File
@@ -1,23 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.mail.tests.common import TestMail
@@ -26,74 +7,39 @@ class TestProjectBase(TestMail):
def setUp(self):
super(TestProjectBase, self).setUp()
cr, uid = self.cr, self.uid
# Usefull models
self.project_project = self.registry('project.project')
self.project_task = self.registry('project.task')
self.project_task_delegate = self.registry('project.task.delegate')
# Find Project User group
group_project_user_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'project', 'group_project_user')
self.group_project_user_id = group_project_user_ref and group_project_user_ref[1] or False
# Find Project Manager group
group_project_manager_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'project', 'group_project_manager')
self.group_project_manager_id = group_project_manager_ref and group_project_manager_ref[1] or False
# Test partners to use through the various tests
self.project_partner_id = self.res_partner.create(cr, uid, {
'name': 'Gertrude AgrolaitPartner',
'email': 'gertrude.partner@agrolait.com',
})
self.email_partner_id = self.res_partner.create(cr, uid, {
'name': 'Patrick Ratatouille',
'email': 'patrick.ratatouille@agrolait.com',
})
user_group_employee = self.env.ref('base.group_user')
user_group_project_user = self.env.ref('project.group_project_user')
user_group_project_manager = self.env.ref('project.group_project_manager')
# Test users to use through the various tests
self.user_projectuser_id = self.res_users.create(cr, uid, {
Users = self.env['res.users'].with_context({'no_reset_password': True})
self.user_projectuser = Users.create({
'name': 'Armande ProjectUser',
'login': 'Armande',
'alias_name': 'armande',
'email': 'armande.projectuser@example.com',
'groups_id': [(6, 0, [self.group_employee_id, self.group_project_user_id])]
'groups_id': [(6, 0, [user_group_employee.id, user_group_project_user.id])]
})
self.user_projectmanager_id = self.res_users.create(cr, uid, {
self.user_projectmanager = Users.create({
'name': 'Bastien ProjectManager',
'login': 'bastien',
'alias_name': 'bastien',
'email': 'bastien.projectmanager@example.com',
'groups_id': [(6, 0, [self.group_employee_id, self.group_project_manager_id])]
})
self.user_none_id = self.res_users.create(cr, uid, {
'name': 'Charlie Avotbonkeur',
'login': 'charlie',
'alias_name': 'charlie',
'email': 'charlie.noone@example.com',
'groups_id': [(6, 0, [])]
})
self.user_projectuser = self.res_users.browse(cr, uid, self.user_projectuser_id)
self.user_projectmanager = self.res_users.browse(cr, uid, self.user_projectmanager_id)
self.partner_projectuser_id = self.user_projectuser.partner_id.id
self.partner_projectmanager_id = self.user_projectmanager.partner_id.id
'groups_id': [(6, 0, [user_group_employee.id, user_group_project_manager.id])]})
# Test 'Pigs' project
self.project_pigs_id = self.project_project.create(cr, uid, {
self.project_pigs = self.env['project.project'].with_context({'mail_create_nolog': True}).create({
'name': 'Pigs',
'privacy_visibility': 'public',
'alias_name': 'project+pigs',
'partner_id': self.partner_raoul_id,
}, {'mail_create_nolog': True})
'partner_id': self.user_employee_2.partner_id.id})
# Already-existing tasks in Pigs
self.task_1_id = self.project_task.create(cr, uid, {
self.task_1 = self.env['project.task'].with_context({'mail_create_nolog': True}).create({
'name': 'Pigs UserTask',
'user_id': self.user_projectuser_id,
'project_id': self.project_pigs_id,
}, {'mail_create_nolog': True})
self.task_2_id = self.project_task.create(cr, uid, {
'user_id': self.user_projectuser.id,
'project_id': self.project_pigs.id})
self.task_2 = self.env['project.task'].with_context({'mail_create_nolog': True}).create({
'name': 'Pigs ManagerTask',
'user_id': self.user_projectmanager_id,
'project_id': self.project_pigs_id,
}, {'mail_create_nolog': True})
'user_id': self.user_projectmanager.id,
'project_id': self.project_pigs.id})
+49 -89
View File
@@ -25,9 +25,9 @@ from openerp.tools import mute_logger
EMAIL_TPL = """Return-Path: <whatever-2a840@postmaster.twitter.com>
X-Original-To: {email_to}
Delivered-To: {email_to}
To: {email_to}
X-Original-To: {to}
Delivered-To: {to}
To: {to}
cc: {cc}
Received: by mail1.openerp.com (Postfix, from userid 10002)
id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST)
@@ -53,120 +53,80 @@ Integrator at Agrolait"""
class TestProjectFlow(TestProjectBase):
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_00_project_process(self):
""" Testing project management """
cr, uid, user_projectuser_id, user_projectmanager_id, project_pigs_id = self.cr, self.uid, self.user_projectuser_id, self.user_projectmanager_id, self.project_pigs_id
def test_project_process_project_user(self):
self.assertRaises(AccessError, self.project_pigs.sudo(self.user_projectuser).set_template)
# ProjectUser: set project as template -> raise
self.assertRaises(AccessError, self.project_project.set_template, cr, user_projectuser_id, [project_pigs_id])
def test_project_process_project_manager_set_template(self):
pigs = self.project_pigs.sudo(self.user_projectmanager)
pigs.set_template()
self.assertEqual(pigs.state, 'template')
self.assertEqual(len(pigs.tasks), 0, 'project: set_template: project tasks should have been set inactive')
# Other tests are done using a ProjectManager
project = self.project_project.browse(cr, user_projectmanager_id, project_pigs_id)
self.assertNotEqual(project.state, 'template', 'project: incorrect state, should not be a template')
# pigs.reset_project()
# self.assertEqual(pigs.state, 'open')
# self.assertEqual(len(pigs.tasks), 2, 'project: reset_project: project tasks should have been set active')
# Set test project as template
self.project_project.set_template(cr, user_projectmanager_id, [project_pigs_id])
project.refresh()
self.assertEqual(project.state, 'template', 'project: set_template: project state should be template')
self.assertEqual(len(project.tasks), 0, 'project: set_template: project tasks should have been set inactive')
# Duplicate template
new_template_act = self.project_project.duplicate_template(cr, user_projectmanager_id, [project_pigs_id])
new_project = self.project_project.browse(cr, user_projectmanager_id, new_template_act['res_id'])
self.assertEqual(new_project.state, 'open', 'project: incorrect duplicate_template')
def test_project_process_project_manager_duplicate(self):
pigs = self.project_pigs.sudo(self.user_projectmanager)
new_template_act = pigs.duplicate_template()
new_project = self.env['project.project'].sudo(self.user_projectmanager).browse(new_template_act['res_id'])
self.assertEqual(new_project.state, 'open')
self.assertEqual(len(new_project.tasks), 2, 'project: duplicating a project template should duplicate its tasks')
# Convert into real project
self.project_project.reset_project(cr, user_projectmanager_id, [project_pigs_id])
project.refresh()
self.assertEqual(project.state, 'open', 'project: resetted project should be in open state')
self.assertEqual(len(project.tasks), 2, 'project: reset_project: project tasks should have been set active')
# Put as pending
self.project_project.set_pending(cr, user_projectmanager_id, [project_pigs_id])
project.refresh()
self.assertEqual(project.state, 'pending', 'project: should be in pending state')
def test_project_process_project_manager_state(self):
pigs = self.project_pigs.sudo(self.user_projectmanager)
pigs.set_pending()
self.assertEqual(pigs.state, 'pending')
# Re-open
self.project_project.set_open(cr, user_projectmanager_id, [project_pigs_id])
project.refresh()
self.assertEqual(project.state, 'open', 'project: reopened project should be in open state')
pigs.set_open()
self.assertEqual(pigs.state, 'open')
# Close project
self.project_project.set_done(cr, user_projectmanager_id, [project_pigs_id])
project.refresh()
self.assertEqual(project.state, 'close', 'project: closed project should be in close state')
pigs.set_done()
self.assertEqual(pigs.state, 'close')
# Re-open
self.project_project.set_open(cr, user_projectmanager_id, [project_pigs_id])
project.refresh()
pigs.set_open()
# Re-convert into a template and schedule tasks
self.project_project.set_template(cr, user_projectmanager_id, [project_pigs_id])
self.project_project.schedule_tasks(cr, user_projectmanager_id, [project_pigs_id])
pigs.set_template()
pigs.schedule_tasks()
# Copy the project
new_project_id = self.project_project.copy(cr, user_projectmanager_id, project_pigs_id)
new_project = self.project_project.browse(cr, user_projectmanager_id, new_project_id)
new_project = pigs.copy()
self.assertEqual(len(new_project.tasks), 2, 'project: copied project should have copied task')
# Cancel the project
self.project_project.set_cancel(cr, user_projectmanager_id, [project_pigs_id])
self.assertEqual(project.state, 'cancelled', 'project: cancelled project should be in cancel state')
def test_10_task_process(self):
""" Testing task creation and management """
cr, uid, user_projectuser_id, user_projectmanager_id, project_pigs_id = self.cr, self.uid, self.user_projectuser_id, self.user_projectmanager_id, self.project_pigs_id
# create new partner
self.partner_id = self.registry('res.partner').create(cr, uid, {
'name': 'Pigs',
'email': 'otherid@gmail.com',
}, {'mail_create_nolog': True})
def format_and_process(template, email_to='project+pigs@mydomain.com, other@gmail.com', cc='otherid@gmail.com', subject='Frogs',
email_from='Patrick Ratatouille <patrick.ratatouille@agrolait.com>',
msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>'):
self.assertEqual(self.project_task.search(cr, uid, [('name', '=', subject)]), [])
mail = template.format(email_to=email_to, cc=cc, subject=subject, email_from=email_from, msg_id=msg_id)
self.mail_thread.message_process(cr, uid, None, mail)
return self.project_task.search(cr, uid, [('name', '=', subject)])
pigs.set_cancel()
self.assertEqual(pigs.state, 'cancelled', 'project: cancelled project should be in cancel state')
@mute_logger('openerp.addons.mail.mail_thread')
def test_task_process(self):
# Do: incoming mail from an unknown partner on an alias creates a new task 'Frogs'
frogs = format_and_process(EMAIL_TPL)
task = self.format_and_process(
EMAIL_TPL, to='project+pigs@mydomain.com, valid.lelitre@agrolait.com', cc='valid.other@gmail.com',
email_from='%s' % self.user_projectuser.email,
subject='Frogs', msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>',
target_model='project.task')
# Test: one task created by mailgateway administrator
self.assertEqual(len(frogs), 1, 'project: message_process: a new project.task should have been created')
task = self.project_task.browse(cr, user_projectuser_id, frogs[0])
self.assertEqual(len(task), 1, 'project: message_process: a new project.task should have been created')
# Test: check partner in message followers
self.assertTrue((self.partner_id in [follower.id for follower in task.message_follower_ids]),"Partner in message cc is not added as a task followers.")
res = self.project_task.get_metadata(cr, uid, [task.id])[0].get('create_uid') or [None]
self.assertEqual(res[0], uid,
'project: message_process: task should have been created by uid as alias_user_id is False on the alias')
self.assertIn(self.partner_2, task.message_follower_ids, "Partner in message cc is not added as a task followers.")
# Test: messages
self.assertEqual(len(task.message_ids), 2,
'project: message_process: newly created task should have 2 messages: creation and email')
self.assertEqual(task.message_ids[1].subtype_id.name, 'Task Opened',
'project: message_process: first message of new task should have Task Created subtype')
self.assertEqual(task.message_ids[0].author_id.id, self.email_partner_id,
self.assertEqual(task.message_ids[0].author_id, self.user_projectuser.partner_id,
'project: message_process: second message should be the one from Agrolait (partner failed)')
self.assertEqual(task.message_ids[0].subject, 'Frogs',
'project: message_process: second message should be the one from Agrolait (subject failed)')
# Test: task content
self.assertEqual(task.name, 'Frogs', 'project_task: name should be the email subject')
self.assertEqual(task.project_id.id, self.project_pigs_id, 'project_task: incorrect project')
self.assertEqual(task.project_id.id, self.project_pigs.id, 'project_task: incorrect project')
self.assertEqual(task.stage_id.sequence, 1, 'project_task: should have a stage with sequence=1')
# Open the delegation wizard
delegate_id = self.project_task_delegate.create(cr, user_projectuser_id, {
'user_id': user_projectuser_id,
'planned_hours': 12.0,
'planned_hours_me': 2.0,
}, {'active_id': task.id})
self.project_task_delegate.delegate(cr, user_projectuser_id, [delegate_id], {'active_id': task.id})
self.env['project.task.delegate'].with_context({
'active_id': task.id}).sudo(self.user_projectuser).create({
'user_id': self.user_projectuser.id,
'planned_hours': 12.0,
'planned_hours_me': 2.0,
}).with_context({'active_id': task.id}).delegate()
# Check delegation details
task.refresh()
self.assertEqual(task.planned_hours, 2, 'project_task_delegate: planned hours is not correct after delegation')
@@ -1,93 +1,46 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.mail.tests.common import TestMail
from openerp.tools import mute_logger
from datetime import datetime
from openerp.tests import common
class TestPurchase(TestMail):
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm')
def setUp(self):
super(TestPurchase, self).setUp()
class TestPurchase(common.TransactionCase):
def test_purchase_to_invoice(self):
""" Testing for invoice create,validate and pay with invoicing and payment user."""
cr, uid = self.cr, self.uid
# Usefull models
data_obj = self.registry('ir.model.data')
user_obj = self.registry('res.users')
partner_obj = self.registry('res.partner')
purchase_obj = self.registry('purchase.order')
purchase_order_line = self.registry('purchase.order.line')
invoice_obj = self.registry('account.invoice')
# Usefull record id
group_id = data_obj.get_object_reference(cr, uid, 'account', 'group_account_invoice')[1]
product_ref = data_obj.get_object_reference(cr, uid, 'product', 'product_category_3')
product_id = product_ref and product_ref[1] or False
company_id = data_obj.get_object_reference(cr, uid, 'base', 'main_company')[1]
location_id = data_obj.get_object_reference(cr, uid, 'stock', 'stock_location_3')[1]
group_id = self.ref('account.group_account_invoice')
product_id = self.ref('product.product_category_3')
company_id = self.ref('base.main_company')
location_id = self.ref('stock.stock_location_3')
# In order to test, I create new user and applied Invoicing & Payments group.
user_id = user_obj.create(cr, uid, {
user = self.env['res.users'].with_context({'no_reset_password': True}).create({
'name': 'Test User',
'login': 'test@test.com',
'company_id': 1,
'groups_id': [(6, 0, [group_id])]
})
assert user_id, "User will not created."
'company_id': company_id,
'groups_id': [(6, 0, [group_id])]})
assert user, "User will not created."
# I create partner for purchase order.
partner_id = partner_obj.create(cr, uid, {
partner = self.env['res.partner'].create({
'name': 'Test Customer',
'email': 'testcustomer@test.com',
})
'email': 'testcustomer@test.com'})
# In order to test I create purchase order and confirmed it.
order_id = purchase_obj.create(cr, uid, {
'partner_id': partner_id,
order = self.env['purchase.order'].create({
'partner_id': partner.id,
'location_id': location_id,
'pricelist_id': 1,
})
order_line = purchase_order_line.create(cr, uid, {
'order_id': order_id,
'product_id': product_id,
'product_qty': 100.0,
'product_uom': 1,
'price_unit': 89.0,
'name': 'Service',
'date_planned': '2014-05-31',
})
assert order_id, "purchase order will not created."
context = {"active_model": 'purchase.order', "active_ids": [order_id], "active_id":order_id}
purchase_obj.wkf_confirm_order(cr, uid, [order_id], context=context)
'pricelist_id': 1})
self.env['purchase.order.line'].create({
'order_id': order.id,
'product_id': product_id,
'product_qty': 100.0,
'product_uom': 1,
'price_unit': 89.0,
'name': 'Service',
'date_planned': '2014-05-31'})
assert order, "purchase order will not created."
context = {"active_model": 'purchase.order', "active_ids": [order.id], "active_id": order.id}
order.with_context(context).wkf_confirm_order()
# In order to test I create invoice.
invoice_id = purchase_obj.action_invoice_create(cr, uid, [order_id], context=context)
assert invoice_id,"No any invoice is created for this purchase order"
invoice = order.with_context(context).action_invoice_create()
assert invoice, "No any invoice is created for this purchase order"
# In order to test I validate invoice wihth Test User(invoicing and payment).
res = invoice_obj.invoice_validate(cr, uid, [invoice_id], context=context)
res = self.env['account.invoice'].browse(invoice).with_context(context).invoice_validate()
self.assertTrue(res, 'Invoice will not validated')
+31 -55
View File
@@ -26,82 +26,58 @@ from datetime import datetime
class TestSale(TestMail):
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm')
def setUp(self):
super(TestSale, self).setUp()
def test_sale_to_invoice(self):
""" Testing for invoice create,validate and pay with invoicing and payment user."""
cr, uid = self.cr, self.uid
# Usefull models
data_obj = self.registry('ir.model.data')
user_obj = self.registry('res.users')
partner_obj = self.registry('res.partner')
sale_obj = self.registry('sale.order')
sale_order_line = self.registry('sale.order.line')
sale_advance_payment_inv = self.registry('sale.advance.payment.inv')
invoice_obj = self.registry('account.invoice')
voucher_obj = self.registry('account.voucher')
IrModelData = self.env['ir.model.data']
# Usefull record id
group_id = data_obj.get_object_reference(cr, uid, 'account', 'group_account_invoice')[1]
product_ref = data_obj.get_object_reference(cr, uid, 'product', 'product_category_3')
product_id = product_ref and product_ref[1] or False
account_id = data_obj.get_object_reference(cr, uid, 'account', 'cash')[1]
company_id = data_obj.get_object_reference(cr, uid, 'base', 'main_company')[1]
journal_id = data_obj.get_object_reference(cr, uid, 'account', 'bank_journal')[1]
period_id = data_obj.get_object_reference(cr, uid, 'account', 'period_8')[1]
group_id = IrModelData.xmlid_to_res_id('account.group_account_invoice') or False
product_id = IrModelData.xmlid_to_res_id('product.product_category_3') or False
account_id = IrModelData.xmlid_to_res_id('account.cash') or False
company_id = IrModelData.xmlid_to_res_id('base.main_company') or False
journal_id = IrModelData.xmlid_to_res_id('account.bank_journal') or False
period_id = IrModelData.xmlid_to_res_id('account.period_8') or False
# In order to test, I create new user and applied Invoicing & Payments group.
user_id = user_obj.create(cr, uid, {
user = self.env['res.users'].create({
'name': 'Test User',
'login': 'test@test.com',
'company_id': 1,
'groups_id': [(6, 0, [group_id])]
})
assert user_id, "User will not created."
'groups_id': [(6, 0, [group_id])]})
assert user, "User will not created."
# I create partner for sale order.
partner_id = partner_obj.create(cr, uid, {
partner = self.env['res.partner'].create({
'name': 'Test Customer',
'email': 'testcustomer@test.com',
})
'email': 'testcustomer@test.com'})
# In order to test I create sale order and confirmed it.
order_id = sale_obj.create(cr, uid, {
'partner_id': partner_id,
'date_order': datetime.today(),
})
order_line = sale_order_line.create(cr, uid, {
'order_id': order_id,
'product_id': product_id,
})
assert order_id, "Sale order will not created."
context = {"active_model": 'sale.order', "active_ids": [order_id], "active_id":order_id}
sale_obj.action_button_confirm(cr, uid, [order_id], context=context)
order = self.env['sale.order'].create({
'partner_id': partner.id,
'date_order': datetime.today()})
order_line = self.env['sale.order.line'].create({
'order_id': order.id,
'product_id': product_id})
assert order, "Sale order will not created."
context = {"active_model": 'sale.order', "active_ids": [order.id], "active_id": order.id}
order.with_context(context).action_button_confirm()
# Now I create invoice.
pay_id = sale_advance_payment_inv.create(cr, uid, {'advance_payment_method': 'fixed', 'amount': 5})
inv = sale_advance_payment_inv.create_invoices(cr, uid, [pay_id], context=context)
invoice_ids = sale_obj.browse(cr, uid, order_id).invoice_ids
assert invoice_ids,"No any invoice is created for this sale order"
payment = self.env['sale.advance.payment.inv'].create({'advance_payment_method': 'fixed', 'amount': 5})
invoice = payment.with_context(context).create_invoices()
assert order.invoice_ids, "No any invoice is created for this sale order"
# Now I validate pay invoice wihth Test User(invoicing and payment).
for invoice in invoice_ids:
invoice_obj.invoice_validate(cr, uid, [invoice.id], context=context)
for invoice in order.invoice_ids:
invoice.with_context(context).invoice_validate()
# Now I create and post an account voucher of amount 75.0 for the partner Test Customer.
voucher_id = voucher_obj.create(cr, uid, {
voucher = self.env['account.voucher'].create({
'account_id': account_id,
'amount': 75.0,
'company_id': company_id,
'journal_id': journal_id,
'partner_id': partner_id,
'partner_id': partner.id,
'period_id': period_id,
'type': 'receipt',
})
assert voucher_id,"Voucher will not created."
voucher = voucher_obj.browse(cr, uid, voucher_id)
assert voucher, "Voucher will not created."
voucher.signal_workflow('proforma_voucher')
@@ -1,23 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2013-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.addons.portal_project.tests.test_access_rights import TestPortalProjectBase
from openerp.exceptions import AccessError
@@ -28,31 +9,28 @@ class TestPortalProjectBase(TestPortalProjectBase):
def setUp(self):
super(TestPortalProjectBase, self).setUp()
cr, uid = self.cr, self.uid
# Useful models
self.project_issue = self.registry('project.issue')
# Various test issues
self.issue_1_id = self.project_issue.create(cr, uid, {
'name': 'Test1', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.issue_2_id = self.project_issue.create(cr, uid, {
'name': 'Test2', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.issue_3_id = self.project_issue.create(cr, uid, {
'name': 'Test3', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.issue_4_id = self.project_issue.create(cr, uid, {
'name': 'Test4', 'user_id': self.user_projectuser_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.issue_5_id = self.project_issue.create(cr, uid, {
'name': 'Test5', 'user_id': self.user_portal_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
self.issue_6_id = self.project_issue.create(cr, uid, {
'name': 'Test6', 'user_id': self.user_public_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
Issue = self.env['project.issue'].with_context({'mail_create_nolog': True})
self.issue_1 = Issue.create({
'name': 'Test1', 'user_id': False, 'project_id': self.project_pigs.id})
self.issue_2 = Issue.create({
'name': 'Test2', 'user_id': False, 'project_id': self.project_pigs.id})
self.issue_3 = Issue.create({
'name': 'Test3', 'user_id': False, 'project_id': self.project_pigs.id})
self.issue_4 = Issue.create({
'name': 'Test4', 'user_id': self.user_projectuser.id, 'project_id': self.project_pigs.id})
self.issue_5 = Issue.create({
'name': 'Test5', 'user_id': self.user_portal.id, 'project_id': self.project_pigs.id})
self.issue_6 = Issue.create({
'name': 'Test6', 'user_id': self.user_public.id, 'project_id': self.project_pigs.id})
class TestPortalIssue(TestPortalProjectBase):
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_00_project_access_rights(self):
""" Test basic project access rights, for project and portal_project """
cr, uid, pigs_id = self.cr, self.uid, self.project_pigs_id
pigs_id = self.project_pigs.id
Issue = self.env['project.issue']
# ----------------------------------------
# CASE1: public project
@@ -60,117 +38,115 @@ class TestPortalIssue(TestPortalProjectBase):
# Do: Alfred reads project -> ok (employee ok public)
# Test: all project issues visible
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
test_issue_ids = set([self.issue_1_id, self.issue_2_id, self.issue_3_id, self.issue_4_id, self.issue_5_id, self.issue_6_id])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_projectuser.id).search([('project_id', '=', pigs_id)])
test_issue_ids = set([self.issue_1.id, self.issue_2.id, self.issue_3.id, self.issue_4.id, self.issue_5.id, self.issue_6.id])
self.assertEqual(set(issues.ids), test_issue_ids,
'access rights: project user cannot see all issues of a public project')
# Test: all project issues readable
self.project_issue.read(cr, self.user_projectuser_id, issue_ids, ['name'])
issues.read(['name'])
# Test: all project issues writable
self.project_issue.write(cr, self.user_projectuser_id, issue_ids, {'description': 'TestDescription'})
issues.sudo(self.user_projectuser.id).write({'description': 'TestDescription'})
# Do: Bert reads project -> crash, no group
# Test: no project issue visible
self.assertRaises(AccessError, self.project_issue.search, cr, self.user_none_id, [('project_id', '=', pigs_id)])
self.assertRaises(AccessError, Issue.sudo(self.user_noone.id).search, [('project_id', '=', pigs_id)])
# Test: no project issue readable
self.assertRaises(AccessError, self.project_issue.read, cr, self.user_none_id, issue_ids, ['name'])
self.assertRaises(AccessError, issues.sudo(self.user_noone.id).read, ['name'])
# Test: no project issue writable
self.assertRaises(AccessError, self.project_issue.write, cr, self.user_none_id, issue_ids, {'description': 'TestDescription'})
self.assertRaises(AccessError, issues.sudo(self.user_noone.id).write, {'description': 'TestDescription'})
# Do: Chell reads project -> ok (portal ok public)
# Test: all project issues visible
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_portal.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), test_issue_ids,
'access rights: project user cannot see all issues of a public project')
# Test: all project issues readable
self.project_issue.read(cr, self.user_portal_id, issue_ids, ['name'])
issues.sudo(self.user_portal.id).read(['name'])
# Test: no project issue writable
self.assertRaises(AccessError, self.project_issue.write, cr, self.user_portal_id, issue_ids, {'description': 'TestDescription'})
self.assertRaises(AccessError, issues.sudo(self.user_portal.id).write, {'description': 'TestDescription'})
# Do: Donovan reads project -> ok (public ok public)
# Test: all project issues visible
issue_ids = self.project_issue.search(cr, self.user_public_id, [('project_id', '=', pigs_id)])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_public.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), test_issue_ids,
'access rights: project user cannot see all issues of a public project')
# ----------------------------------------
# CASE2: portal project
# ----------------------------------------
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'portal'})
self.project_pigs.write({'privacy_visibility': 'portal'})
# Do: Alfred reads project -> ok (employee ok public)
# Test: all project issues visible
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_projectuser.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), test_issue_ids,
'access rights: project user cannot see all issues of a portal project')
# Do: Bert reads project -> crash, no group
# Test: no project issue searchable
self.assertRaises(AccessError, self.project_issue.search, cr, self.user_none_id, [('project_id', '=', pigs_id)])
self.assertRaises(AccessError, Issue.sudo(self.user_noone.id).search, [('project_id', '=', pigs_id)])
# Data: issue follower
self.project_issue.message_subscribe_users(cr, self.user_projectuser_id, [self.issue_1_id, self.issue_3_id], [self.user_portal_id])
self.issue_1.sudo(self.user_projectuser.id).message_subscribe_users(user_ids=[self.user_portal.id])
self.issue_3.sudo(self.user_projectuser.id).message_subscribe_users(user_ids=[self.user_portal.id])
# Do: Chell reads project -> ok (portal ok public)
# Test: only followed project issues visible + assigned
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
test_issue_ids = set([self.issue_1_id, self.issue_3_id, self.issue_5_id])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_portal.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), set([self.issue_1.id, self.issue_3.id, self.issue_5.id]),
'access rights: portal user should see the followed issues of a portal project')
# Data: issue follower cleaning
self.project_issue.message_unsubscribe_users(cr, self.user_projectuser_id, [self.issue_1_id, self.issue_3_id], [self.user_portal_id])
self.issue_1.sudo(self.user_projectuser.id).message_unsubscribe_users(user_ids=[self.user_portal.id])
self.issue_3.sudo(self.user_projectuser.id).message_unsubscribe_users(user_ids=[self.user_portal.id])
# ----------------------------------------
# CASE3: employee project
# ----------------------------------------
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'employees'})
self.project_pigs.write({'privacy_visibility': 'employees'})
# Do: Alfred reads project -> ok (employee ok employee)
# Test: all project issues visible
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
test_issue_ids = set([self.issue_1_id, self.issue_2_id, self.issue_3_id, self.issue_4_id, self.issue_5_id, self.issue_6_id])
self.assertEqual(set(issue_ids), test_issue_ids,
'access rights: project user cannot see all issues of an employees project')
issues = Issue.sudo(self.user_projectuser.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), set([self.issue_1.id, self.issue_2.id, self.issue_3.id,
self.issue_4.id, self.issue_5.id, self.issue_6.id]),
'access rights: project user cannot see all issues of an employees project')
# Do: Chell reads project -> ko (portal ko employee)
# Test: no project issue visible + assigned
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
self.assertFalse(issue_ids, 'access rights: portal user should not see issues of an employees project, even if assigned')
issues = Issue.sudo(self.user_portal.id).search([('project_id', '=', pigs_id)])
self.assertFalse(issues.ids, 'access rights: portal user should not see issues of an employees project, even if assigned')
# ----------------------------------------
# CASE4: followers project
# ----------------------------------------
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'followers'})
self.project_pigs.write({'privacy_visibility': 'followers'})
# Do: Alfred reads project -> ko (employee ko followers)
# Test: no project issue visible
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
test_issue_ids = set([self.issue_4_id])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_projectuser.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), set([self.issue_4.id]),
'access rights: employee user should not see issues of a not-followed followers project, only assigned')
# Do: Chell reads project -> ko (portal ko employee)
# Test: no project issue visible
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
test_issue_ids = set([self.issue_5_id])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_portal.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), set([self.issue_5.id]),
'access rights: portal user should not see issues of a not-followed followers project, only assigned')
# Data: subscribe Alfred, Chell and Donovan as follower
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_projectuser_id, self.user_portal_id, self.user_public_id])
self.project_issue.message_subscribe_users(cr, self.user_manager_id, [self.issue_1_id, self.issue_3_id], [self.user_portal_id, self.user_projectuser_id])
self.project_pigs.message_subscribe_users(user_ids=[self.user_projectuser.id, self.user_portal.id, self.user_public.id])
self.issue_1.sudo(self.user_projectmanager.id).message_subscribe_users(user_ids=[self.user_portal.id, self.user_projectuser.id])
self.issue_3.sudo(self.user_projectmanager.id).message_subscribe_users(user_ids=[self.user_portal.id, self.user_projectuser.id])
# Do: Alfred reads project -> ok (follower ok followers)
# Test: followed + assigned issues visible
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
test_issue_ids = set([self.issue_1_id, self.issue_3_id, self.issue_4_id])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_projectuser.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), set([self.issue_1.id, self.issue_3.id, self.issue_4.id]),
'access rights: employee user should not see followed + assigned issues of a follower project')
# Do: Chell reads project -> ok (follower ok follower)
# Test: followed + assigned issues visible
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
test_issue_ids = set([self.issue_1_id, self.issue_3_id, self.issue_5_id])
self.assertEqual(set(issue_ids), test_issue_ids,
issues = Issue.sudo(self.user_portal.id).search([('project_id', '=', pigs_id)])
self.assertEqual(set(issues.ids), set([self.issue_1.id, self.issue_3.id, self.issue_5.id]),
'access rights: employee user should not see followed + assigned issues of a follower project')