diff options
| author | Jignesh Rathod <jir@openerp.com> | 2015-03-24 10:18:16 +0100 |
|---|---|---|
| committer | Thibault Delavallée <tde@openerp.com> | 2015-03-24 10:18:16 +0100 |
| commit | b55969a577fe59245228cb0aba2b63f1e8e61927 (patch) | |
| tree | d3e58af39578b5167cbf56412c23014c6a658607 /addons | |
| parent | 573341c906e56d05a0c6ba001a82af40055bae63 (diff) | |
[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.
Diffstat (limited to 'addons')
22 files changed, 1877 insertions, 3078 deletions
diff --git a/addons/mail/tests/__init__.py b/addons/mail/tests/__init__.py index 23162ee1c2f..fcd18424f8a 100644 --- a/addons/mail/tests/__init__.py +++ b/addons/mail/tests/__init__.py @@ -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 diff --git a/addons/mail/tests/common.py b/addons/mail/tests/common.py index 7856c021851..4d2b0dfe731 100644 --- a/addons/mail/tests/common.py +++ b/addons/mail/tests/common.py @@ -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) - - # 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 + self.env['ir.mail_server']._patch_method('build_email', build_email) + self.env['ir.mail_server']._patch_method('send_email', send_email) + + # 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_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'}) + self.user_admin.company_id.write({ + 'name': self._company_name, + }) + + # 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() diff --git a/addons/mail/tests/test_invite.py b/addons/mail/tests/test_invite.py index c4484d254bb..5daa6ea784c 100644 --- a/addons/mail/tests/test_invite.py +++ b/addons/mail/tests/test_invite.py @@ -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') diff --git a/addons/mail/tests/test_ir_actions.py b/addons/mail/tests/test_ir_actions.py index fdfa2201d15..bb08fdc7101 100644 --- a/addons/mail/tests/test_ir_actions.py +++ b/addons/mail/tests/test_ir_actions.py @@ -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') diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py deleted file mode 100644 index 657b8ec1df1..00000000000 --- a/addons/mail/tests/test_mail.py +++ /dev/null @@ -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') diff --git a/addons/mail/tests/test_mail_features.py b/addons/mail/tests/test_mail_features.py index d8f2f90a7da..fd1e1ea7672 100644 --- a/addons/mail/tests/test_mail_features.py +++ b/addons/mail/tests/test_mail_features.py @@ -1,903 +1,405 @@ # -*- 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.mail_mail import mail_mail -from openerp.addons.mail.mail_thread import mail_thread + from openerp.addons.mail.tests.common import TestMail -from openerp.tools import mute_logger, email_split, html2plaintext -from openerp.tools.mail import html_sanitize - -class test_mail(TestMail): - - def test_000_alias_setup(self): - """ Test basic mail.alias setup works, before trying to use them for routing """ - cr, uid = self.cr, self.uid - self.user_valentin_id = self.res_users.create(cr, uid, - {'name': 'Valentin Cognito', 'email': 'valentin.cognito@gmail.com', 'login': 'valentin.cognito', 'alias_name': 'valentin.cognito'}) - self.user_valentin = self.res_users.browse(cr, uid, self.user_valentin_id) - self.assertEquals(self.user_valentin.alias_name, self.user_valentin.login, "Login should be used as alias") - - self.user_pagan_id = self.res_users.create(cr, uid, - {'name': 'Pagan Le Marchant', 'email': 'plmarchant@gmail.com', 'login': 'plmarchant@gmail.com', 'alias_name': 'plmarchant@gmail.com'}) - self.user_pagan = self.res_users.browse(cr, uid, self.user_pagan_id) - self.assertEquals(self.user_pagan.alias_name, 'plmarchant', "If login is an email, the alias should keep only the local part") - - self.user_barty_id = self.res_users.create(cr, uid, - {'name': 'Bartholomew Ironside', 'email': 'barty@gmail.com', 'login': 'b4r+_#_R3wl$$', 'alias_name': 'b4r+_#_R3wl$$'}) - self.user_barty = self.res_users.browse(cr, uid, self.user_barty_id) - self.assertEquals(self.user_barty.alias_name, 'b4r+_-_r3wl-', 'Disallowed chars should be replaced by hyphens') - - def test_00_followers_function_field(self): - """ Tests designed for the many2many function field 'follower_ids'. - We will test to perform writes using the many2many commands 0, 3, 4, - 5 and 6. """ - cr, uid, user_admin, partner_bert_id, group_pigs = self.cr, self.uid, self.user_admin, self.partner_bert_id, self.group_pigs - - # Data: create 'disturbing' values in mail.followers: same res_id, other res_model; same res_model, other res_id - group_dummy_id = self.mail_group.create(cr, uid, - {'name': 'Dummy group'}, {'mail_create_nolog': True}) - self.mail_followers.create(cr, uid, - {'res_model': 'mail.thread', 'res_id': self.group_pigs_id, 'partner_id': partner_bert_id}) - self.mail_followers.create(cr, uid, - {'res_model': 'mail.group', 'res_id': group_dummy_id, 'partner_id': partner_bert_id}) - - # Pigs just created: should be only Admin as follower - follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) - self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan') - - # Subscribe Bert through a '4' command - group_pigs.write({'message_follower_ids': [(4, partner_bert_id)]}) - group_pigs.refresh() - follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) - self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the only Pigs fans') - - # Unsubscribe Bert through a '3' command - group_pigs.write({'message_follower_ids': [(3, partner_bert_id)]}) - group_pigs.refresh() - follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) - self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan') - - # Set followers through a '6' command - group_pigs.write({'message_follower_ids': [(6, 0, [partner_bert_id])]}) - group_pigs.refresh() - follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) - self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the only Pigs fan') - - # Add a follower created on the fly through a '0' command - group_pigs.write({'message_follower_ids': [(0, 0, {'name': 'Patrick Fiori'})]}) - partner_patrick_id = self.res_partner.search(cr, uid, [('name', '=', 'Patrick Fiori')])[0] - group_pigs.refresh() - follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) - self.assertEqual(follower_ids, set([partner_bert_id, partner_patrick_id]), 'Bert and Patrick should be the only Pigs fans') - - # Finally, unlink through a '5' command - group_pigs.write({'message_follower_ids': [(5, 0)]}) - group_pigs.refresh() - follower_ids = set([follower.id for follower in group_pigs.message_follower_ids]) - self.assertFalse(follower_ids, 'Pigs group should not have fans anymore') - - # Test dummy data has not been altered - fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.thread'), ('res_id', '=', self.group_pigs_id)]) - follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)]) - self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the follower of dummy mail.thread data') - fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', group_dummy_id)]) - follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)]) - self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the followers of dummy mail.group data') - - def test_05_message_followers_and_subtypes(self): - """ Tests designed for the subscriber API as well as message subtypes """ - cr, uid, user_admin, user_raoul, group_pigs = self.cr, self.uid, self.user_admin, self.user_raoul, self.group_pigs - # Data: message subtypes - self.mail_message_subtype.create(cr, uid, {'name': 'mt_mg_def', 'default': True, 'res_model': 'mail.group'}) - self.mail_message_subtype.create(cr, uid, {'name': 'mt_other_def', 'default': True, 'res_model': 'crm.lead'}) - self.mail_message_subtype.create(cr, uid, {'name': 'mt_all_def', 'default': True, 'res_model': False}) - mt_mg_nodef = self.mail_message_subtype.create(cr, uid, {'name': 'mt_mg_nodef', 'default': False, 'res_model': 'mail.group'}) - mt_all_nodef = self.mail_message_subtype.create(cr, uid, {'name': 'mt_all_nodef', 'default': False, 'res_model': False}) - default_group_subtypes = self.mail_message_subtype.search(cr, uid, [('default', '=', True), '|', ('res_model', '=', 'mail.group'), ('res_model', '=', False)]) - - # ---------------------------------------- - # CASE1: test subscriptions with subtypes - # ---------------------------------------- - - # Do: subscribe Raoul, should have default subtypes - group_pigs.message_subscribe_users([user_raoul.id]) - group_pigs.refresh() - # Test: 2 followers (Admin and Raoul) - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertEqual(set(follower_ids), set([user_raoul.partner_id.id, user_admin.partner_id.id]), - 'message_subscribe: Admin and Raoul should be the only 2 Pigs fans') - # Raoul follows default subtypes - fol_ids = self.mail_followers.search(cr, uid, [ - ('res_model', '=', 'mail.group'), - ('res_id', '=', self.group_pigs_id), - ('partner_id', '=', user_raoul.partner_id.id) - ]) - fol_obj = self.mail_followers.browse(cr, uid, fol_ids)[0] - fol_subtype_ids = set([subtype.id for subtype in fol_obj.subtype_ids]) - self.assertEqual(set(fol_subtype_ids), set(default_group_subtypes), - 'message_subscribe: Raoul subscription subtypes are incorrect, should be all default ones') - - # Do: subscribe Raoul with specified new subtypes - group_pigs.message_subscribe_users([user_raoul.id], subtype_ids=[mt_mg_nodef]) - # Test: 2 followers (Admin and Raoul) - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertEqual(set(follower_ids), set([user_raoul.partner_id.id, user_admin.partner_id.id]), - 'message_subscribe: Admin and Raoul should be the only 2 Pigs fans') - # Test: 2 lines in mail.followers (no duplicate for Raoul) - fol_ids = self.mail_followers.search(cr, uid, [ - ('res_model', '=', 'mail.group'), - ('res_id', '=', self.group_pigs_id), - ]) - self.assertEqual(len(fol_ids), 2, - 'message_subscribe: subscribing an already-existing follower should not create new entries in mail.followers') - # Test: Raoul follows only specified subtypes - fol_ids = self.mail_followers.search(cr, uid, [ - ('res_model', '=', 'mail.group'), - ('res_id', '=', self.group_pigs_id), - ('partner_id', '=', user_raoul.partner_id.id) - ]) - fol_obj = self.mail_followers.browse(cr, uid, fol_ids)[0] - fol_subtype_ids = set([subtype.id for subtype in fol_obj.subtype_ids]) - self.assertEqual(set(fol_subtype_ids), set([mt_mg_nodef]), - 'message_subscribe: Raoul subscription subtypes are incorrect, should be only specified') - - # Do: Subscribe Raoul without specified subtypes: should not erase existing subscription subtypes - group_pigs.message_subscribe_users([user_raoul.id, user_raoul.id]) - group_pigs.message_subscribe_users([user_raoul.id]) - group_pigs.refresh() - # Test: 2 followers (Admin and Raoul) - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertEqual(set(follower_ids), set([user_raoul.partner_id.id, user_admin.partner_id.id]), - 'message_subscribe: Admin and Raoul should be the only 2 Pigs fans') - # Test: Raoul follows default subtypes - fol_ids = self.mail_followers.search(cr, uid, [ - ('res_model', '=', 'mail.group'), - ('res_id', '=', self.group_pigs_id), - ('partner_id', '=', user_raoul.partner_id.id) - ]) - fol_obj = self.mail_followers.browse(cr, uid, fol_ids)[0] - fol_subtype_ids = set([subtype.id for subtype in fol_obj.subtype_ids]) - self.assertEqual(set(fol_subtype_ids), set([mt_mg_nodef]), - 'message_subscribe: Raoul subscription subtypes are incorrect, should be only specified') - - # Do: Unsubscribe Raoul twice through message_unsubscribe_users - group_pigs.message_unsubscribe_users([user_raoul.id, user_raoul.id]) - group_pigs.refresh() - # Test: 1 follower (Admin) - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertEqual(follower_ids, [user_admin.partner_id.id], 'Admin must be the only Pigs fan') - # Test: 1 lines in mail.followers (no duplicate for Raoul) - fol_ids = self.mail_followers.search(cr, uid, [ - ('res_model', '=', 'mail.group'), - ('res_id', '=', self.group_pigs_id) - ]) - self.assertEqual(len(fol_ids), 1, - 'message_subscribe: group should have only 1 entry in mail.follower for 1 follower') - - # Do: subscribe Admin with subtype_ids - group_pigs.message_subscribe_users([uid], [mt_mg_nodef, mt_all_nodef]) - fol_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id), ('partner_id', '=', user_admin.partner_id.id)]) - fol_obj = self.mail_followers.browse(cr, uid, fol_ids)[0] - fol_subtype_ids = set([subtype.id for subtype in fol_obj.subtype_ids]) - self.assertEqual(set(fol_subtype_ids), set([mt_mg_nodef, mt_all_nodef]), 'subscription subtypes are incorrect') - - # ---------------------------------------- - # CASE2: test mail_thread fields - # ---------------------------------------- - - subtype_data = group_pigs._get_subscription_data(None, None)[group_pigs.id]['message_subtype_data'] - self.assertEqual(set(subtype_data.keys()), set(['Discussions', 'mt_mg_def', 'mt_all_def', 'mt_mg_nodef', 'mt_all_nodef']), 'mail.group available subtypes incorrect') - self.assertFalse(subtype_data['Discussions']['followed'], 'Admin should not follow Discussions in pigs') - self.assertTrue(subtype_data['mt_mg_nodef']['followed'], 'Admin should follow mt_mg_nodef in pigs') - self.assertTrue(subtype_data['mt_all_nodef']['followed'], 'Admin should follow mt_all_nodef in pigs') - - def test_11_notification_url(self): - """ Tests designed to test the URL added in notification emails. """ - cr, uid, group_pigs = self.cr, self.uid, self.group_pigs - # Test URL formatting - base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') - - # 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) - # Mail data - mail_mail_id = self.mail_mail.create(cr, uid, {'state': 'exception'}) - mail = self.mail_mail.browse(cr, uid, mail_mail_id) - - # Test: link for nobody -> None - url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail) - self.assertEqual(url, None, - 'notification email: mails not send to a specific partner should not have any URL') - - # Test: link for partner -> None - url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail, partner=partner_bert) - self.assertEqual(url, None, - 'notification email: mails send to a not-user partner should not have any URL') - - # Test: link for user -> signin - url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail, partner=partner_raoul) - self.assertIn(base_url, url, - 'notification email: link should contain web.base.url') - self.assertIn('db=%s' % cr.dbname, url, +from openerp.tools import mute_logger + + +class TestMailFeatures(TestMail): + + def test_alias_setup(self): + Users = self.env['res.users'].with_context({'no_reset_password': True}) + + user_valentin = Users.create({ + 'name': 'Valentin Cognito', 'email': 'valentin.cognito@gmail.com', + 'login': 'valentin.cognito', 'alias_name': 'valentin.cognito'}) + self.assertEqual(user_valentin.alias_name, user_valentin.login, "Login should be used as alias") + + user_pagan = Users.create({ + 'name': 'Pagan Le Marchant', 'email': 'plmarchant@gmail.com', + 'login': 'plmarchant@gmail.com', 'alias_name': 'plmarchant@gmail.com'}) + self.assertEqual(user_pagan.alias_name, 'plmarchant', "If login is an email, the alias should keep only the local part") + + user_barty = Users.create({ + 'name': 'Bartholomew Ironside', 'email': 'barty@gmail.com', + 'login': 'b4r+_#_R3wl$$', 'alias_name': 'b4r+_#_R3wl$$'}) + self.assertEqual(user_barty.alias_name, 'b4r+_-_r3wl-', 'Disallowed chars should be replaced by hyphens') + + def test_mail_notification_url_no_partner(self): + mail = self.env['mail.mail'].create({'state': 'exception'}) + url = self.env['mail.mail']._get_partner_access_link(mail) + self.assertEqual(url, None) + + def test_mail_notification_url_partner(self): + mail = self.env['mail.mail'].create({'state': 'exception'}) + url = self.env['mail.mail']._get_partner_access_link(mail, self.partner_1) + self.assertEqual(url, None) + + def test_mail_notification_url_user_signin(self): + base_url = self.env['ir.config_parameter'].get_param('web.base.url') + mail = self.env['mail.mail'].create({'state': 'exception'}) + url = self.env['mail.mail']._get_partner_access_link(mail, self.user_employee.partner_id) + self.assertIn(base_url, url) + self.assertIn('db=%s' % self.env.cr.dbname, url, 'notification email: link should contain database name') 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, + self.assertIn('login=%s' % self.user_employee.login, url, 'notification email: link should contain the user login') - # Test: link for user -> with model and res_id - mail_mail_id = self.mail_mail.create(cr, uid, {'model': 'mail.group', 'res_id': group_pigs.id}) - mail = self.mail_mail.browse(cr, uid, mail_mail_id) - url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail, partner=partner_raoul) - self.assertIn(base_url, url, - 'notification email: link should contain web.base.url') - self.assertIn('db=%s' % cr.dbname, url, + def test_mail_notification_url_user_document(self): + base_url = self.env['ir.config_parameter'].get_param('web.base.url') + mail = self.env['mail.mail'].create({'state': 'exception', 'model': 'mail.group', 'res_id': self.group_pigs.id}) + url = self.env['mail.mail']._get_partner_access_link(mail, self.user_employee.partner_id) + self.assertIn(base_url, url) + self.assertIn('db=%s' % self.env.cr.dbname, url, 'notification email: link should contain database name') 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, + self.assertIn('login=%s' % self.user_employee.login, url, 'notification email: link should contain the user login') self.assertIn('model=mail.group', url, 'notification email: link should contain the model when having not notification email on a record') - self.assertIn('res_id=%s' % group_pigs.id, url, + self.assertIn('res_id=%s' % self.group_pigs.id, url, 'notification email: link should contain the res_id when having not notification email on a record') - # Test: link for user -> with model and res_id - mail_mail_id = self.mail_mail.create(cr, uid, {'notification': True, 'model': 'mail.group', 'res_id': group_pigs.id}) - mail = self.mail_mail.browse(cr, uid, mail_mail_id) - url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail, partner=partner_raoul) - self.assertIn(base_url, url, - 'notification email: link should contain web.base.url') - self.assertIn('db=%s' % cr.dbname, url, - 'notification email: link should contain database name') - 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') - self.assertIn('message_id=%s' % mail.mail_message_id.id, url, - 'notification email: link based on message should contain the mail_message id') - self.assertNotIn('model=mail.group', url, - 'notification email: link based on message should not contain model') - self.assertNotIn('res_id=%s' % group_pigs.id, url, - 'notification email: link based on message should not contain res_id') - - @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') - def test_12_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') - # Data: post a message on pigs - msg_id = self.group_pigs.message_post(body='My body', partner_ids=[self.partner_bert_id], type='comment', subtype='mail.mt_comment') - - # No specific parameters -> should redirect to Inbox - action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_raoul_id, {'params': {}}) + def test_inbox_redirection_basic(self): + """ Inbox redirection: no params, Inbox """ + inbox_act_id = self.ref('mail.action_mail_inbox_feeds') + action = self.env['mail.thread'].with_context({'params': {}}).sudo(self.user_employee).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'), act_id, + action.get('id'), inbox_act_id, 'URL redirection: action without parameters should redirect to client action Inbox' ) - # Raoul has read access to Pigs -> should redirect to form view of Pigs - action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_raoul_id, {'params': {'message_id': msg_id}}) + def test_inbox_redirection_document(self): + """ Inbox redirection: document + read access: Doc """ + action = self.env['mail.thread'].with_context({ + 'params': {'model': 'mail.group', 'res_id': self.group_pigs.id} + }).sudo(self.user_employee).message_redirect_action() 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, + action.get('res_id'), self.group_pigs.id, 'URL redirection: action with message_id for read-accredited user should redirect to Pigs' ) - action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_raoul_id, {'params': {'model': 'mail.group', 'res_id': group_pigs.id}}) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_inbox_redirection_message_document(self): + """ Inbox redirection: message + read access: Doc """ + msg_id = self.group_pigs.message_post(body='My body', partner_ids=[self.user_employee.partner_id.id], type='comment', subtype='mail.mt_comment') + action = self.env['mail.thread'].with_context({ + 'params': {'message_id': msg_id} + }).sudo(self.user_employee).message_redirect_action() 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, + action.get('res_id'), self.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 = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_bert_id, {'params': {'message_id': msg_id}}) + @mute_logger('openerp.addons.mail.mail_mail', 'openerp.models') + def test_inbox_redirection_message_inbox(self): + """ Inbox redirection: message without read access: Inbox """ + msg_id = self.group_pigs.message_post(body='My body', partner_ids=[self.user_employee.partner_id.id], type='comment', subtype='mail.mt_comment') + inbox_act_id = self.ref('mail.action_mail_inbox_feeds') + action = self.env['mail.thread'].with_context({ + 'params': {'message_id': msg_id} + }).sudo(self.user_public).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'), act_id, + action.get('id'), inbox_act_id, 'URL redirection: action without parameters should redirect to client action Inbox' ) - action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_bert_id, {'params': {'model': 'mail.group', 'res_id': group_pigs.id}}) + + @mute_logger('openerp.models') + def test_inbox_redirection_document_inbox(self): + """ Inbox redirection: document without read access: Inbox """ + inbox_act_id = self.ref('mail.action_mail_inbox_feeds') + action = self.env['mail.thread'].with_context({ + 'params': {'model': 'mail.group', 'res_id': self.group_pigs.id} + }).sudo(self.user_public).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'), act_id, + action.get('id'), inbox_act_id, 'URL redirection: action without parameters should redirect to client action Inbox' ) - def test_20_message_post(self): - """ Tests designed for message_post. """ - cr, uid, user_raoul, group_pigs = self.cr, self.uid, self.user_raoul, self.group_pigs - - # -------------------------------------------------- - # Data creation - # -------------------------------------------------- - # 0 - Update existing users-partners - self.res_users.write(cr, uid, [uid], {'email': 'a@a', 'notify_email': 'always'}) - self.res_users.write(cr, uid, [self.user_raoul_id], {'email': 'r@r'}) - # 1 - Bert Tartopoils, with email, should receive emails for comments and emails - p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'}) - # 2 - Carine Poilvache, with email, should receive emails for emails - p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notify_email': 'none'}) - # 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message - p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'email': 'd@d', 'notify_email': 'always'}) - # 4 - Attachments - attach1_id = self.ir_attachment.create(cr, user_raoul.id, { + @mute_logger('openerp.addons.mail.mail_mail') + def test_needaction(self): + na_emp1_base = self.env['mail.message'].sudo(self.user_employee)._needaction_count(domain=[]) + na_emp2_base = self.env['mail.message'].sudo(self.user_employee_2)._needaction_count(domain=[]) + + self.group_pigs.message_post(body='Test', type='comment', subtype='mail.mt_comment', partner_ids=[self.user_employee.partner_id.id]) + + na_emp1_new = self.env['mail.message'].sudo(self.user_employee)._needaction_count(domain=[]) + na_emp2_new = self.env['mail.message'].sudo(self.user_employee_2)._needaction_count(domain=[]) + self.assertEqual(na_emp1_new, na_emp1_base + 1) + self.assertEqual(na_emp2_new, na_emp2_base) + + no_notify = self.env['mail.notification'].search_count([ + ('partner_id', '=', self.user_employee.partner_id.id), + ('is_read', '=', False)]) + self.assertEqual(no_notify, na_emp1_new) + + +class TestMessagePost(TestMail): + + def setUp(self): + super(TestMessagePost, self).setUp() + self._attach_1 = self.env['ir.attachment'].sudo(self.user_employee).create({ 'name': 'Attach1', 'datas_fname': 'Attach1', 'datas': 'bWlncmF0aW9uIHRlc3Q=', 'res_model': 'mail.compose.message', 'res_id': 0}) - attach2_id = self.ir_attachment.create(cr, user_raoul.id, { + self._attach_2 = self.env['ir.attachment'].sudo(self.user_employee).create({ 'name': 'Attach2', 'datas_fname': 'Attach2', 'datas': 'bWlncmF0aW9uIHRlc3Q=', 'res_model': 'mail.compose.message', 'res_id': 0}) - attach3_id = self.ir_attachment.create(cr, user_raoul.id, { + self._attach_3 = self.env['ir.attachment'].sudo(self.user_employee).create({ 'name': 'Attach3', 'datas_fname': 'Attach3', 'datas': 'bWlncmF0aW9uIHRlc3Q=', 'res_model': 'mail.compose.message', 'res_id': 0}) - # 5 - Mail data - _subject = 'Pigs' - _mail_subject = 'Re: %s' % (group_pigs.name) - _body1 = '<p>Pigs rules</p>' - _body2 = '<html>Pigs rocks</html>' + self.group_pigs.message_subscribe_users(user_ids=self.user_employee.id) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_post_no_subscribe_author(self): + original_followers = self.group_pigs.message_follower_ids + self.group_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True}).message_post( + body='Test Body', type='comment', subtype='mt_comment') + self.assertEqual(self.group_pigs.message_follower_ids, original_followers) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_post_subscribe_author(self): + original_followers = self.group_pigs.message_follower_ids + self.group_pigs.sudo(self.user_employee).message_post( + body='Test Body', type='comment', subtype='mt_comment') + self.assertEqual(self.group_pigs.message_follower_ids, original_followers | self.user_employee.partner_id) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_post_no_subscribe_recipients(self): + original_followers = self.group_pigs.message_follower_ids + self.group_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True}).message_post( + body='Test Body', type='comment', subtype='mt_comment', partner_ids=[(4, self.partner_1.id), (4, self.partner_2.id)]) + self.assertEqual(self.group_pigs.message_follower_ids, original_followers) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_post_subscribe_recipients(self): + original_followers = self.group_pigs.message_follower_ids + self.group_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True, 'mail_post_autofollow': True}).message_post( + body='Test Body', type='comment', subtype='mt_comment', partner_ids=[(4, self.partner_1.id), (4, self.partner_2.id)]) + self.assertEqual(self.group_pigs.message_follower_ids, original_followers | self.partner_1 | self.partner_2) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_post_subscribe_recipients_partial(self): + original_followers = self.group_pigs.message_follower_ids + self.group_pigs.sudo(self.user_employee).with_context({'mail_create_nosubscribe': True, 'mail_post_autofollow': True, 'mail_post_autofollow_partner_ids': [self.partner_2.id]}).message_post( + body='Test Body', type='comment', subtype='mt_comment', partner_ids=[(4, self.partner_1.id), (4, self.partner_2.id)]) + self.assertEqual(self.group_pigs.message_follower_ids, original_followers | self.partner_2) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_post_notifications(self): + _body, _body_alt = '<p>Test Body</p>', 'Test Body' + _subject = 'Test Subject' _attachments = [ ('List1', 'My first attachment'), ('List2', 'My second attachment') ] - - # -------------------------------------------------- - # CASE1: post comment + partners + attachments - # -------------------------------------------------- - - # Data: set alias_domain to see emails with alias - self.registry('ir.config_parameter').set_param(self.cr, self.uid, 'mail.catchall.domain', 'schlouby.fr') - # Data: change Pigs name to test reply_to - self.mail_group.write(cr, uid, [self.group_pigs_id], {'name': '"Pigs" !ù $%-'}) - - # Do: subscribe Raoul - new_follower_ids = [self.partner_raoul_id] - group_pigs.message_subscribe(new_follower_ids) - # Test: group followers = Raoul + uid - group_fids = [follower.id for follower in group_pigs.message_follower_ids] - test_fids = new_follower_ids + [self.partner_admin_id] - self.assertEqual(set(test_fids), set(group_fids), - 'message_subscribe: incorrect followers after subscribe') - - # Do: Raoul message_post on Pigs - self._init_mock_build_email() - msg1_id = self.mail_group.message_post(cr, user_raoul.id, self.group_pigs_id, - body=_body1, subject=_subject, partner_ids=[p_b_id, p_c_id], - attachment_ids=[attach1_id, attach2_id], attachments=_attachments, - type='comment', subtype='mt_comment') - msg = self.mail_message.browse(cr, uid, msg1_id) - msg_message_id = msg.message_id - msg_pids = [partner.id for partner in msg.notified_partner_ids] - msg_aids = [attach.id for attach in msg.attachment_ids] - sent_emails = self._build_email_kwargs_list - - # Test: mail_message: subject and body not modified - self.assertEqual(_subject, msg.subject, 'message_post: mail.message subject incorrect') - self.assertEqual(_body1, msg.body, 'message_post: mail.message body incorrect') - # Test: mail_message: notified_partner_ids = group followers + partner_ids - author - test_pids = set([self.partner_admin_id, p_b_id, p_c_id]) - self.assertEqual(test_pids, set(msg_pids), 'message_post: mail.message notified partners incorrect') - # Test: mail_message: attachments (4, attachment_ids + attachments) - test_aids = set([attach1_id, attach2_id]) - msg_attach_names = set([attach.name for attach in msg.attachment_ids]) - test_attach_names = set(['Attach1', 'Attach2', 'List1', 'List2']) - self.assertEqual(len(msg_aids), 4, - 'message_post: mail.message wrong number of attachments') - self.assertEqual(msg_attach_names, test_attach_names, - 'message_post: mail.message attachments incorrectly added') - self.assertTrue(test_aids.issubset(set(msg_aids)), + # partner_2 does not want to receive notification email + self.partner_2.write({'notify_email': 'none'}) + # subscribe second employee to the group to test notifications + self.group_pigs.message_subscribe_users(user_ids=self.user_employee_2.id) + + # use aliases + _domain = 'schlouby.fr' + _catchall = 'test_catchall' + self.env['ir.config_parameter'].set_param('mail.catchall.domain', _domain) + self.env['ir.config_parameter'].set_param('mail.catchall.alias', _catchall) + + msg_id = self.group_pigs.sudo(self.user_employee).message_post( + body=_body, subject=_subject, partner_ids=[self.partner_1.id, self.partner_2.id], + attachment_ids=[self._attach_1.id, self._attach_2.id], attachments=_attachments, + type='comment', subtype='mt_comment') + msg = self.env['mail.message'].browse(msg_id) + + # message content + self.assertEqual(msg.subject, _subject) + self.assertEqual(msg.body, _body) + self.assertEqual(msg.partner_ids, self.partner_1 | self.partner_2) + self.assertEqual(msg.notified_partner_ids, self.partner_1 | self.partner_2 | self.user_employee_2.partner_id) + # attachments + self.assertEqual(set(msg.attachment_ids.mapped('res_model')), set(['mail.group']), + 'message_post: all atttachments should be linked to the mail.group model') + self.assertEqual(set(msg.attachment_ids.mapped('res_id')), set([self.group_pigs.id]), + 'message_post: all atttachments should be linked to the pigs group') + self.assertEqual(set([x.decode('base64') for x in msg.attachment_ids.mapped('datas')]), + set(['migration test', _attachments[0][1], _attachments[1][1]])) + self.assertTrue(set([self._attach_1.id, self._attach_2.id]).issubset(msg.attachment_ids.ids), 'message_post: mail.message attachments duplicated') - for attach in msg.attachment_ids: - self.assertEqual(attach.res_model, 'mail.group', - 'message_post: mail.message attachments were not linked to the document') - self.assertEqual(attach.res_id, group_pigs.id, - 'message_post: mail.message attachments were not linked to the document') - if 'List' in attach.name: - self.assertIn((attach.name, attach.datas.decode('base64')), _attachments, - 'message_post: mail.message attachment name / data incorrect') - dl_attach = self.mail_message.download_attachment(cr, user_raoul.id, id_message=msg.id, attachment_id=attach.id) - self.assertIn((dl_attach['filename'], dl_attach['base64'].decode('base64')), _attachments, - 'message_post: mail.message download_attachment is incorrect') - - # Test: followers: same as before (author was already subscribed) - group_pigs.refresh() - group_fids = [follower.id for follower in group_pigs.message_follower_ids] - test_fids = new_follower_ids + [self.partner_admin_id] - self.assertEqual(set(test_fids), set(group_fids), - 'message_post: wrong followers after posting') - - # Test: mail_mail: notifications have been deleted - self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg1_id)]), - 'message_post: mail.mail notifications should have been auto-deleted!') - - # Test: notifications emails: to a and b, c is email only, r is author - test_emailto = ['Administrator <a@a>', 'Bert Tartopoils <b@b>'] - # test_emailto = ['"Followers of -Pigs-" <a@a>', '"Followers of -Pigs-" <b@b>'] - self.assertEqual(len(sent_emails), 2, - 'message_post: notification emails wrong number of send emails') - self.assertEqual(set([m['email_to'][0] for m in sent_emails]), set(test_emailto), - 'message_post: notification emails wrong recipients (email_to)') - for sent_email in sent_emails: - self.assertEqual(sent_email['email_from'], 'Raoul Grosbedon <raoul@schlouby.fr>', - 'message_post: notification email wrong email_from: should use alias of sender') - self.assertEqual(len(sent_email['email_to']), 1, - 'message_post: notification email sent to more than one email address instead of a precise partner') - self.assertIn(sent_email['email_to'][0], test_emailto, - 'message_post: notification email email_to incorrect') - self.assertEqual(sent_email['reply_to'], u'"YourCompany \\"Pigs\\" !ù $%-" <group+pigs@schlouby.fr>', - 'message_post: notification email reply_to incorrect') - self.assertEqual(_subject, sent_email['subject'], - 'message_post: notification email subject incorrect') - self.assertIn(_body1, sent_email['body'], - 'message_post: notification email body incorrect') - self.assertIn('Pigs rules', sent_email['body_alternative'], - 'message_post: notification email body alternative should contain the body') - self.assertNotIn('<p>', sent_email['body_alternative'], - 'message_post: notification email body alternative still contains html') - self.assertFalse(sent_email['references'], - 'message_post: references should be False when sending a message that is not a reply') - - # Test: notification linked to this message = group followers = notified_partner_ids - notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', msg1_id)]) - notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)]) - self.assertEqual(notif_pids, test_pids, - 'message_post: mail.message created mail.notification incorrect') - - # Data: Pigs name back to normal - self.mail_group.write(cr, uid, [self.group_pigs_id], {'name': 'Pigs'}) - - # -------------------------------------------------- - # CASE2: reply + parent_id + parent notification - # -------------------------------------------------- - - # Data: remove alias_domain to see emails with alias - param_ids = self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.domain')]) - self.registry('ir.config_parameter').unlink(cr, uid, param_ids) - - # Do: Raoul message_post on Pigs - self._init_mock_build_email() - msg2_id = self.mail_group.message_post(cr, user_raoul.id, self.group_pigs_id, - body=_body2, type='email', subtype='mt_comment', - partner_ids=[p_d_id], parent_id=msg1_id, attachment_ids=[attach3_id], - context={'mail_post_autofollow': True}) - msg = self.mail_message.browse(cr, uid, msg2_id) - msg_pids = [partner.id for partner in msg.notified_partner_ids] - msg_aids = [attach.id for attach in msg.attachment_ids] - sent_emails = self._build_email_kwargs_list - - # Test: mail_message: subject is False, body, parent_id is msg_id - self.assertEqual(msg.subject, False, 'message_post: mail.message subject incorrect') - self.assertEqual(msg.body, html_sanitize(_body2), 'message_post: mail.message body incorrect') - self.assertEqual(msg.parent_id.id, msg1_id, 'message_post: mail.message parent_id incorrect') - # Test: mail_message: notified_partner_ids = group followers - test_pids = [self.partner_admin_id, p_d_id] - self.assertEqual(set(test_pids), set(msg_pids), 'message_post: mail.message partners incorrect') - # Test: mail_message: notifications linked to this message = group followers = notified_partner_ids - notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', msg2_id)]) - notif_pids = [notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)] - self.assertEqual(set(test_pids), set(notif_pids), 'message_post: mail.message notification partners incorrect') - - # Test: mail_mail: notifications deleted - self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg2_id)]), 'mail.mail notifications should have been auto-deleted!') - - # Test: emails send by server (to a, b, c, d) - test_emailto = [u'Administrator <a@a>', u'Bert Tartopoils <b@b>', u'Carine Poilvache <c@c>', u'D\xe9d\xe9 Grosbedon <d@d>'] - # test_emailto = [u'"Followers of Pigs" <a@a>', u'"Followers of Pigs" <b@b>', u'"Followers of Pigs" <c@c>', u'"Followers of Pigs" <d@d>'] - # self.assertEqual(len(sent_emails), 3, 'sent_email number of sent emails incorrect') - for sent_email in sent_emails: - self.assertEqual(sent_email['email_from'], 'Raoul Grosbedon <r@r>', - 'message_post: notification email wrong email_from: should use email of sender when no alias domain set') - self.assertEqual(len(sent_email['email_to']), 1, - 'message_post: notification email sent to more than one email address instead of a precise partner') - self.assertIn(sent_email['email_to'][0], test_emailto, - 'message_post: notification email email_to incorrect') - self.assertEqual(email_split(sent_email['reply_to']), ['r@r'], # was '"Followers of Pigs" <r@r>', but makes no sense - 'message_post: notification email reply_to incorrect: should have raoul email') - self.assertEqual(_mail_subject, sent_email['subject'], - 'message_post: notification email subject incorrect') - self.assertIn(html_sanitize(_body2), sent_email['body'], - 'message_post: notification email does not contain the body') - self.assertIn('Pigs rocks', sent_email['body_alternative'], - 'message_post: notification email body alternative should contain the body') - self.assertNotIn('<p>', sent_email['body_alternative'], - 'message_post: notification email body alternative still contains html') - self.assertIn(msg_message_id, sent_email['references'], - 'message_post: notification email references lacks parent message message_id') - # Test: attachments + download - for attach in msg.attachment_ids: - self.assertEqual(attach.res_model, 'mail.group', - 'message_post: mail.message attachment res_model incorrect') - self.assertEqual(attach.res_id, self.group_pigs_id, - 'message_post: mail.message attachment res_id incorrect') - - # Test: Dédé has been notified -> should also have been notified of the parent message - msg = self.mail_message.browse(cr, uid, msg1_id) - msg_pids = set([partner.id for partner in msg.notified_partner_ids]) - test_pids = set([self.partner_admin_id, p_b_id, p_c_id, p_d_id]) - self.assertEqual(test_pids, msg_pids, 'message_post: mail.message parent notification not created') - - # Do: reply to last message - msg3_id = self.mail_group.message_post(cr, user_raoul.id, self.group_pigs_id, body='Test', parent_id=msg2_id) - msg = self.mail_message.browse(cr, uid, msg3_id) - # Test: check that its parent will be the first message - self.assertEqual(msg.parent_id.id, msg1_id, 'message_post did not flatten the thread structure') - - def test_25_message_compose_wizard(self): - """ Tests designed for the mail.compose.message wizard. """ - cr, uid, user_raoul, group_pigs = self.cr, self.uid, self.user_raoul, self.group_pigs - mail_compose = self.registry('mail.compose.message') - - # -------------------------------------------------- - # Data creation - # -------------------------------------------------- - # 0 - Update existing users-partners - self.res_users.write(cr, uid, [uid], {'email': 'a@a'}) - self.res_users.write(cr, uid, [self.user_raoul_id], {'email': 'r@r'}) - # 1 - Bert Tartopoils, with email, should receive emails for comments and emails - p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'}) - # 2 - Carine Poilvache, with email, should receive emails for emails - p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notify_email': 'always'}) - # 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message - p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'email': 'd@d', 'notify_email': 'always'}) - # 4 - Create a Bird mail.group, that will be used to test mass mailing - group_bird_id = self.mail_group.create(cr, uid, - { - 'name': 'Bird', - 'description': 'Bird resistance', - }, context={'mail_create_nolog': True}) - group_bird = self.mail_group.browse(cr, uid, group_bird_id) - # 5 - Mail data - _subject = 'Pigs' - _body = 'Pigs <b>rule</b>' - _reply_subject = 'Re: %s' % _subject - _attachments = [ - {'name': 'First', 'datas_fname': 'first.txt', 'datas': 'My first attachment'.encode('base64')}, - {'name': 'Second', 'datas_fname': 'second.txt', 'datas': 'My second attachment'.encode('base64')} - ] - _attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')] - # 6 - Subscribe Bert to Pigs - group_pigs.message_subscribe([p_b_id]) - - # -------------------------------------------------- - # CASE1: wizard + partners + context keys - # -------------------------------------------------- - - # Do: Raoul wizard-composes on Pigs with auto-follow for partners, not for author - compose_id = mail_compose.create(cr, user_raoul.id, - { - 'subject': _subject, - 'body': _body, - 'partner_ids': [(4, p_c_id), (4, p_d_id)], - }, context={ - 'default_composition_mode': 'comment', - 'default_model': 'mail.group', - 'default_res_id': self.group_pigs_id, - }) - compose = mail_compose.browse(cr, uid, compose_id) - - # Test: mail.compose.message: composition_mode, model, res_id - self.assertEqual(compose.composition_mode, 'comment', 'compose wizard: mail.compose.message incorrect composition_mode') - self.assertEqual(compose.model, 'mail.group', 'compose wizard: mail.compose.message incorrect model') - self.assertEqual(compose.res_id, self.group_pigs_id, 'compose wizard: mail.compose.message incorrect res_id') - - # Do: Post the comment - mail_compose.send_mail(cr, user_raoul.id, [compose_id], context={'mail_post_autofollow': True, 'mail_create_nosubscribe': True}) - group_pigs.refresh() - message = group_pigs.message_ids[0] - # Test: mail_mail: notifications have been deleted - self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', message.id)]),'message_send: mail.mail message should have been auto-deleted!') - # Test: mail.group: followers (c and d added by auto follow key; raoul not added by nosubscribe key) - pigs_pids = [p.id for p in group_pigs.message_follower_ids] - test_pids = [self.partner_admin_id, p_b_id, p_c_id, p_d_id] - self.assertEqual(set(pigs_pids), set(test_pids), - 'compose wizard: mail_post_autofollow and mail_create_nosubscribe context keys not correctly taken into account') - - # Test: mail.message: subject, body inside p - self.assertEqual(message.subject, _subject, 'compose wizard: mail.message incorrect subject') - self.assertEqual(message.body, '<p>%s</p>' % _body, 'compose wizard: mail.message incorrect body') - # Test: mail.message: notified_partner_ids = admin + bert (followers) + c + d (recipients) - msg_pids = [partner.id for partner in message.notified_partner_ids] - test_pids = [self.partner_admin_id, p_b_id, p_c_id, p_d_id] - self.assertEqual(set(msg_pids), set(test_pids), - 'compose wizard: mail.message notified_partner_ids incorrect') - - # -------------------------------------------------- - # CASE2: reply + attachments - # -------------------------------------------------- - - # Do: Reply with attachments - compose_id = mail_compose.create(cr, user_raoul.id, - { - 'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])] - }, context={ - 'default_composition_mode': 'comment', - 'default_res_id': self.group_pigs_id, - 'default_parent_id': message.id - }) - compose = mail_compose.browse(cr, uid, compose_id) - - # Test: mail.compose.message: model, res_id, parent_id - self.assertEqual(compose.model, 'mail.group', 'compose wizard: mail.compose.message incorrect model') - self.assertEqual(compose.res_id, self.group_pigs_id, 'compose wizard: mail.compose.message incorrect res_id') - self.assertEqual(compose.parent_id.id, message.id, 'compose wizard: mail.compose.message incorrect parent_id') - - # Test: mail.compose.message: subject as Re:.., body, parent_id - self.assertEqual(compose.subject, _reply_subject, 'compose wizard: mail.compose.message incorrect subject') - self.assertFalse(compose.body, 'compose wizard: mail.compose.message body should not contain parent message body') - self.assertEqual(compose.parent_id and compose.parent_id.id, message.id, 'compose wizard: mail.compose.message parent_id incorrect') - # Test: mail.compose.message: attachments - for attach in compose.attachment_ids: - self.assertIn((attach.datas_fname, attach.datas.decode('base64')), _attachments_test, - 'compose wizard: mail.message attachment name / data incorrect') - - # -------------------------------------------------- - # CASE3: mass_mail on Pigs and Bird - # -------------------------------------------------- - - # Do: Compose in mass_mail_mode on pigs and bird - compose_id = mail_compose.create( - cr, user_raoul.id, { - 'subject': _subject, - 'body': '${object.description}', - 'partner_ids': [(4, p_c_id), (4, p_d_id)], - }, context={ - 'default_composition_mode': 'mass_mail', - 'default_model': 'mail.group', - 'default_res_id': False, - 'active_ids': [self.group_pigs_id, group_bird_id], - }) - compose = mail_compose.browse(cr, uid, compose_id) - - # Do: Post the comment, get created message for each group - mail_compose.send_mail(cr, user_raoul.id, [compose_id], context={ - 'default_res_id': -1, - 'active_ids': [self.group_pigs_id, group_bird_id] - }) + # notifications + self.assertFalse(self.env['mail.mail'].search([('mail_message_id', '=', msg.message_id)]), + 'message_post: mail.mail notifications should have been auto-deleted') + + # notification emails: followers + recipients - notify_email=none (partner_2) - author (user_employee) + self.assertEqual(set(m['email_from'] for m in self._mails), + set(['%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, _domain)]), + 'message_post: notification email wrong email_from: should use alias of sender') + self.assertEqual(set(m['email_to'][0] for m in self._mails), + set(['%s <%s>' % (self.partner_1.name, self.partner_1.email), + '%s <%s>' % (self.user_employee_2.name, self.user_employee_2.email)])) + self.assertFalse(any(len(m['email_to']) != 1 for m in self._mails), + 'message_post: notification email should be sent to one partner at a time') + self.assertEqual(set(m['reply_to'] for m in self._mails), + set(['%s %s <%s@%s>' % (self._company_name, self.group_pigs.name, self.group_pigs.alias_name, _domain)]), + 'message_post: notification email should use group aliases and data for reply to') + self.assertTrue(all(_subject in m['subject'] for m in self._mails)) + self.assertTrue(all(_body in m['body'] for m in self._mails)) + self.assertTrue(all(_body_alt in m['body'] for m in self._mails)) + self.assertFalse(any(m['references'] for m in self._mails)) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_post_answer(self): + _body = '<p>Test Body</p>' + _subject = 'Test Subject' + + # use aliases + _domain = 'schlouby.fr' + _catchall = 'test_catchall' + self.env['ir.config_parameter'].set_param('mail.catchall.domain', _domain) + self.env['ir.config_parameter'].set_param('mail.catchall.alias', _catchall) + + parent_msg_id = self.group_pigs.sudo(self.user_employee).message_post( + body=_body, subject=_subject, + type='comment', subtype='mt_comment') + parent_msg = self.env['mail.message'].browse(parent_msg_id) + + self.assertEqual(parent_msg.notified_partner_ids, self.env['res.partner']) + + msg_id = self.group_pigs.sudo(self.user_employee).message_post( + body=_body, subject=_subject, partner_ids=[self.partner_1.id], + type='comment', subtype='mt_comment', parent_id=parent_msg_id) + msg = self.env['mail.message'].browse(msg_id) + + self.assertEqual(msg.parent_id.id, parent_msg_id) + self.assertEqual(msg.notified_partner_ids, self.partner_1) + self.assertEqual(parent_msg.notified_partner_ids, self.partner_1) + self.assertTrue(all('openerp-%d-mail.group' % self.group_pigs.id in m['references'] for m in self._mails)) + new_msg_id = self.group_pigs.sudo(self.user_employee).message_post( + body=_body, subject=_subject, + type='comment', subtype='mt_comment', parent_id=msg_id) + new_msg = self.env['mail.message'].browse(new_msg_id) + + self.assertEqual(new_msg.parent_id.id, parent_msg_id, 'message_post: flatten error') + self.assertFalse(new_msg.notified_partner_ids) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_message_compose(self): + composer = self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'comment', + 'default_model': 'mail.group', + 'default_res_id': self.group_pigs.id, + }).sudo(self.user_employee).create({ + 'body': '<p>Test Body</p>', + 'partner_ids': [(4, self.partner_1.id), (4, self.partner_2.id)] + }) + self.assertEqual(composer.composition_mode, 'comment') + self.assertEqual(composer.model, 'mail.group') + self.assertEqual(composer.subject, 'Re: %s' % self.group_pigs.name) + self.assertEqual(composer.record_name, self.group_pigs.name) + + composer.send_mail() + message = self.group_pigs.message_ids[0] + + composer = self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'comment', + 'default_res_id': self.group_pigs.id, + 'default_parent_id': message.id + }).sudo(self.user_employee).create({}) + + self.assertEqual(composer.model, 'mail.group') + self.assertEqual(composer.res_id, self.group_pigs.id) + self.assertEqual(composer.parent_id, message) + self.assertEqual(composer.subject, 'Re: %s' % self.group_pigs.name) + + # TODO: test attachments ? + + @mute_logger('openerp.addons.mail.mail_mail') + def test_message_compose_mass_mail(self): + composer = self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'mass_mail', + 'default_model': 'mail.group', + 'default_res_id': False, + 'active_ids': [self.group_pigs.id, self.group_public.id] + }).sudo(self.user_employee).create({ + 'subject': 'Testing ${object.name}', + 'body': '<p>${object.description}</p>', + 'partner_ids': [(4, self.partner_1.id), (4, self.partner_2.id)] + }) + composer.with_context({ + 'default_res_id': -1, + 'active_ids': [self.group_pigs.id, self.group_public.id] + }).send_mail() + # check mail_mail - mail_mail_ids = self.mail_mail.search(cr, uid, [('subject', '=', _subject)]) - for mail_mail in self.mail_mail.browse(cr, uid, mail_mail_ids): - self.assertEqual(set([p.id for p in mail_mail.recipient_ids]), set([p_c_id, p_d_id]), + mails = self.env['mail.mail'].search([('subject', 'ilike', 'Testing')]) + for mail in mails: + self.assertEqual(mail.recipient_ids, self.partner_1 | self.partner_2, 'compose wizard: mail_mail mass mailing: mail.mail in mass mail incorrect recipients') - # check logged messages - group_pigs.refresh() - group_bird.refresh() - message1 = group_pigs.message_ids[0] - message2 = group_bird.message_ids[0] - - # Test: Pigs and Bird did receive their message - test_msg_ids = self.mail_message.search(cr, uid, [], limit=2) - mail_ids = self.mail_mail.search(cr, uid, [('mail_message_id', '=', message2.id)]) - mail_record_id = self.mail_mail.browse(cr, uid, mail_ids)[0] - self.assertTrue(mail_record_id, "'message_send: mail.mail message should have in processing mail queue'" ) - #check mass mail state... - test_mail_ids = self.mail_mail.search(cr, uid, [('state', '=', 'exception')]) - self.assertNotIn(mail_ids, test_mail_ids, 'compose wizard: Mail sending Failed!!') - self.assertIn(message1.id, test_msg_ids, 'compose wizard: Pigs did not receive its mass mailing message') - self.assertIn(message2.id, test_msg_ids, 'compose wizard: Bird did not receive its mass mailing message') - - # Test: mail.message: subject, body, subtype, notified partners (nobody + specific recipients) - self.assertEqual(message1.subject, _subject, - 'compose wizard: message_post: mail.message in mass mail subject incorrect') - self.assertEqual(message1.body, '<p>%s</p>' % group_pigs.description, - 'compose wizard: message_post: mail.message in mass mail body incorrect') - # self.assertEqual(set([p.id for p in message1.notified_partner_ids]), set([p_c_id, p_d_id]), - # 'compose wizard: message_post: mail.message in mass mail incorrect notified partners') - self.assertEqual(message2.subject, _subject, - 'compose wizard: message_post: mail.message in mass mail subject incorrect') - self.assertEqual(message2.body, '<p>%s</p>' % group_bird.description, - 'compose wizard: message_post: mail.message in mass mail body incorrect') - # self.assertEqual(set([p.id for p in message2.notified_partner_ids]), set([p_c_id, p_d_id]), - # 'compose wizard: message_post: mail.message in mass mail incorrect notified partners') - + # check message on group_pigs + message1 = self.group_pigs.message_ids[0] + self.assertEqual(message1.subject, 'Testing %s' % self.group_pigs.name) + self.assertEqual(message1.body, '<p>%s</p>' % self.group_pigs.description) + + # check message on group_public + message1 = self.group_public.message_ids[0] + self.assertEqual(message1.subject, 'Testing %s' % self.group_public.name) + self.assertEqual(message1.body, '<p>%s</p>' % self.group_public.description) + + # # Test: Pigs and Bird did receive their message + # # check logged messages + # message1 = group_pigs.message_ids[0] + # message2 = group_bird.message_ids[0] + # # Test: Pigs and Bird did receive their message + # messages = self.MailMessage.search([], limit=2) + # mail = self.MailMail.search([('mail_message_id', '=', message2.id)], limit=1) + # self.assertTrue(mail, 'message_send: mail.mail message should have in processing mail queue') + # #check mass mail state... + # mails = self.MailMail.search([('state', '=', 'exception')]) + # self.assertNotIn(mail.id, mails.ids, 'compose wizard: Mail sending Failed!!') + # self.assertIn(message1.id, messages.ids, 'compose wizard: Pigs did not receive its mass mailing message') + # self.assertIn(message2.id, messages.ids, 'compose wizard: Bird did not receive its mass mailing message') + + # check followers ? # Test: mail.group followers: author not added as follower in mass mail mode - pigs_pids = [p.id for p in group_pigs.message_follower_ids] - test_pids = [self.partner_admin_id, p_b_id, p_c_id, p_d_id] - self.assertEqual(set(pigs_pids), set(test_pids), - 'compose wizard: mail_post_autofollow and mail_create_nosubscribe context keys not correctly taken into account') - bird_pids = [p.id for p in group_bird.message_follower_ids] - test_pids = [self.partner_admin_id] - self.assertEqual(set(bird_pids), set(test_pids), - 'compose wizard: mail_post_autofollow and mail_create_nosubscribe context keys not correctly taken into account') - - # Do: Compose in mass_mail, coming from list_view, we have an active_domain that should be supported - compose_id = mail_compose.create(cr, user_raoul.id, - { - 'subject': _subject, - 'body': '${object.description}', - 'partner_ids': [(4, p_c_id), (4, p_d_id)], - }, context={ - 'default_composition_mode': 'mass_mail', - 'default_model': 'mail.group', - 'default_res_id': False, - 'active_ids': [self.group_pigs_id], - 'active_domain': [('name', 'in', ['Pigs', 'Bird'])], - }) - compose = mail_compose.browse(cr, uid, compose_id) - - # Do: Post the comment, get created message for each group - mail_compose.send_mail( - cr, user_raoul.id, [compose_id], context={ - 'default_res_id': -1, - 'active_ids': [self.group_pigs_id, group_bird_id] - }) - group_pigs.refresh() - group_bird.refresh() - message1 = group_pigs.message_ids[0] - message2 = group_bird.message_ids[0] - - # Test: Pigs and Bird did receive their message - test_msg_ids = self.mail_message.search(cr, uid, [], limit=2) - self.assertIn(message1.id, test_msg_ids, 'compose wizard: Pigs did not receive its mass mailing message') - self.assertIn(message2.id, test_msg_ids, 'compose wizard: Bird did not receive its mass mailing message') - - def test_30_needaction(self): - """ Tests for mail.message needaction. """ - cr, uid, user_admin, user_raoul, group_pigs = self.cr, self.uid, self.user_admin, self.user_raoul, self.group_pigs - na_admin_base = self.mail_message._needaction_count(cr, uid, domain=[]) - na_demo_base = self.mail_message._needaction_count(cr, user_raoul.id, domain=[]) - - # Test: number of unread notification = needaction on mail.message - notif_ids = self.mail_notification.search(cr, uid, [ - ('partner_id', '=', user_admin.partner_id.id), - ('is_read', '=', False) - ]) - na_count = self.mail_message._needaction_count(cr, uid, domain=[]) - self.assertEqual(len(notif_ids), na_count, 'unread notifications count does not match needaction count') - - # Do: post 2 message on group_pigs as admin, 3 messages as demo user - for dummy in range(2): - group_pigs.message_post(body='My Body', subtype='mt_comment') - raoul_pigs = group_pigs.sudo(user_raoul) - for dummy in range(3): - raoul_pigs.message_post(body='My Demo Body', subtype='mt_comment') - - # Test: admin has 3 new notifications (from demo), and 3 new needaction - notif_ids = self.mail_notification.search(cr, uid, [ - ('partner_id', '=', user_admin.partner_id.id), - ('is_read', '=', False) - ]) - self.assertEqual(len(notif_ids), na_admin_base + 3, 'Admin should have 3 new unread notifications') - na_admin = self.mail_message._needaction_count(cr, uid, domain=[]) - na_admin_group = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)]) - self.assertEqual(na_admin, na_admin_base + 3, 'Admin should have 3 new needaction') - self.assertEqual(na_admin_group, 3, 'Admin should have 3 needaction related to Pigs') - # Test: demo has 0 new notifications (not a follower, not receiving its own messages), and 0 new needaction - notif_ids = self.mail_notification.search(cr, uid, [ - ('partner_id', '=', user_raoul.partner_id.id), - ('is_read', '=', False) - ]) - self.assertEqual(len(notif_ids), na_demo_base + 0, 'Demo should have 0 new unread notifications') - na_demo = self.mail_message._needaction_count(cr, user_raoul.id, domain=[]) - na_demo_group = self.mail_message._needaction_count(cr, user_raoul.id, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)]) - self.assertEqual(na_demo, na_demo_base + 0, 'Demo should have 0 new needaction') - self.assertEqual(na_demo_group, 0, 'Demo should have 0 needaction related to Pigs') - - def test_40_track_field(self): - """ Testing auto tracking of fields. """ - def _strip_string_spaces(body): - return body.replace(' ', '').replace('\n', '') - - # Data: subscribe Raoul to Pigs, because he will change the public attribute and may loose access to the record - cr, uid = self.cr, self.uid - self.mail_group.message_subscribe_users(cr, uid, [self.group_pigs_id], [self.user_raoul_id]) - - # Data: res.users.group, to test group_public_id automatic logging - group_system_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_system') - group_system_id = group_system_ref and group_system_ref[1] or False - - # Data: custom subtypes - mt_private_id = self.mail_message_subtype.create(cr, uid, {'name': 'private', 'description': 'Private public'}) - self.ir_model_data.create(cr, uid, {'name': 'mt_private', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_private_id}) - mt_name_supername_id = self.mail_message_subtype.create(cr, uid, {'name': 'name_supername', 'description': 'Supername name'}) - self.ir_model_data.create(cr, uid, {'name': 'mt_name_supername', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_name_supername_id}) - mt_group_public_set_id = self.mail_message_subtype.create(cr, uid, {'name': 'group_public_set', 'description': 'Group set'}) - self.ir_model_data.create(cr, uid, {'name': 'mt_group_public_set', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_group_public_set_id}) - 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}) - - 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.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.mail_group.write(cr, self.user_raoul_id, [self.group_pigs_id], {'public': 'public'}) - self.group_pigs.refresh() - self.assertEqual(len(self.group_pigs.message_ids), 1, 'tracked: a message should have been produced') - # Test: first produced message: group public tracking - 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.mail_group.write(cr, self.user_raoul_id, [self.group_pigs_id], {'name': 'supername', 'public': 'private'}) - self.group_pigs.refresh() - self.assertEqual(len(self.group_pigs.message_ids), 2, 'tracked: one new tracking message 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.mail_group.write(cr, self.user_raoul_id, [self.group_pigs_id], {'public': 'public', 'group_public_id': group_system_id}) - self.group_pigs.refresh() - 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.id, mt_group_public_set_id, '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.mail_group.write(cr, self.user_raoul_id, [self.group_pigs_id], {'group_public_id': False}) - self.group_pigs.refresh() - 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.id, mt_group_public_id, '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.mail_group.write(cr, self.user_raoul_id, [self.group_pigs_id], {'description': 'Dummy'}) - self.group_pigs.refresh() - self.assertEqual(len(self.group_pigs.message_ids), 4, 'tracked: No message should have been produced') + # self.assertEqual(set(group_pigs.message_follower_ids.ids), set([self.partner_admin_id, p_b.id, p_c.id, p_d.id]), + # 'compose wizard: mail_post_autofollow and mail_create_nosubscribe context keys not correctly taken into account') + # self.assertEqual(set(group_bird.message_follower_ids.ids), set([self.partner_admin_id]), + # 'compose wizard: mail_post_autofollow and mail_create_nosubscribe context keys not correctly taken into account') + + @mute_logger('openerp.addons.mail.mail_mail') + def test_message_compose_mass_mail_active_domain(self): + composer = self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'mass_mail', + 'default_model': 'mail.group', + 'active_ids': [self.group_pigs.id], + 'active_domain': [('name', 'in', ['%s' % self.group_pigs.name, '%s' % self.group_public.name])], + }).sudo(self.user_employee).create({ + 'subject': 'From Composer Test', + 'body': '${object.description}', + }).send_mail() + + self.assertEqual(self.group_pigs.message_ids[0].subject, 'From Composer Test') + self.assertEqual(self.group_public.message_ids[0].subject, 'From Composer Test') diff --git a/addons/mail/tests/test_mail_followers.py b/addons/mail/tests/test_mail_followers.py new file mode 100644 index 00000000000..f389aa9c32e --- /dev/null +++ b/addons/mail/tests/test_mail_followers.py @@ -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']) diff --git a/addons/mail/tests/test_mail_gateway.py b/addons/mail/tests/test_mail_gateway.py index cc732b007a2..507786ba86c 100644 --- a/addons/mail/tests/test_mail_gateway.py +++ b/addons/mail/tests/test_mail_gateway.py @@ -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 +class TestMailgateway(TestMail): - 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 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 + 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') + # 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, + self.assertEqual(len(self._mails), 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, + @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') - # 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') + @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') + # 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') - - # -------------------------------------------------- - # Test2: update-like alias - # -------------------------------------------------- - - # 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, - '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') + self.assertEqual(len(new_groups), 1, 'message_process: a new mail.group should have been created') - # 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, - 'message_process: one email should have been generated') - self.assertIn('test.sylvie.lelitre@agrolait.com', sent_emails[0].get('email_to')[0], - 'message_process: email should be sent to Sylvie') - self.mail_group.message_unsubscribe(cr, uid, [frog_group.id], [p2id]) + @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}) - # -------------------------------------------------- - # Test3: discussion and replies - # -------------------------------------------------- + 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') - # 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, + # 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: one new message - self.assertEqual(len(frog_group.message_ids), 3, 'message_process: group should contain 3 messages after reply') + 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('valid.lelitre@agrolait.com', self._mails[0].get('email_to')[0], + 'message_process: email should be sent to Sylvie') # 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') - - # 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}) + 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())) + + # 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 - # -------------------------------------------------- - - # 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'}) - - # 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') - - # 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') - - # 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') - - # 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.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_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'}) + + 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]) + + from_2 = self.env['res.users'].with_context({'no_reset_password': True}).create({'name': 'B', 'login': 'B', 'email': 'from.test@example.com'}) + + self.format_and_process(MAIL_TEMPLATE, to='public@example.com', msg_id='<2>', email_from='Brice Denisse <from.test@example.com>') + self.assertEqual(self.group_public.message_ids[0].author_id, from_2.partner_id, 'message_process: email_from -> author_id wrong') + self.group_public.message_unsubscribe(partner_ids=[from_2.id]) + + from_3 = self.env['res.partner'].create({'name': 'C', 'email': 'from.test@example.com'}) + self.group_public.message_subscribe(partner_ids=[from_3.id]) + + self.format_and_process(MAIL_TEMPLATE, to='public@example.com', msg_id='<3>', email_from='Brice Denisse <from.test@example.com>') + self.assertEqual(self.group_public.message_ids[0].author_id, from_3, 'message_process: email_from -> author_id wrong') + + @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') - - # 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), - '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') + 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_bert_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), + 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') diff --git a/addons/mail/tests/test_mail_group.py b/addons/mail/tests/test_mail_group.py index 25a4d5b199e..4aed947dbab 100644 --- a/addons/mail/tests/test_mail_group.py +++ b/addons/mail/tests/test_mail_group.py @@ -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 + # 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() + + # 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() + + # Create group: ko, no access rights 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]) + self.env['mail.group'].sudo(self.user_public).create({'name': 'Test'}) - # Do: Bert creates a group -> ko, no access rights + # Update 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]) - - # Do: Raoul reads Priv -> ko, private + self.group_public.sudo(self.user_public).write({'name': 'Broutouschnouk'}) + + # Unlink 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]) - - # 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) + 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.mail_group.write(cr, user_noone_id, [self.group_priv_id], {'name': 're-modified'}) - # Test: Bert cannot unlink the group + self.group_private.sudo(self.user_employee).write({'name': 're-modified'}) + + def test_access_rights_followers_ko(self): 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_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 diff --git a/addons/mail/tests/test_mail_message.py b/addons/mail/tests/test_mail_message.py index 3bd089bd87c..6e9f6eb8987 100644 --- a/addons/mail/tests/test_mail_message.py +++ b/addons/mail/tests/test_mail_message.py @@ -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 - - # 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>' - - # -------------------------------------------------- - # 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) - - # 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') - - # 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') - - # 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') - - # -------------------------------------------------- - # 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')])) - - # 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') - - # 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') - - # -------------------------------------------------- - # Case2: with alias_domain and catchall alias - # -------------------------------------------------- - self.registry('ir.config_parameter').set_param(self.cr, self.uid, 'mail.catchall.alias', 'gateway') - - # 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') - - # 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') - - @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 - - # 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 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)], + }) + + def test_mail_message_values_basic(self): + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() + + 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') + + def test_mail_message_values_default(self): + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() + + 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)) + + 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() + + 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)) + + 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) + + 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)) + + def test_mail_message_values_document_no_alias(self): + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() + + 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)) + + 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() + + 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_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}) - - # 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') + 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: 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') - # 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'].sudo(self.user_employee).search([('subject', 'like', '_Test')]) + self.assertEqual(messages, msg3 | msg4 | msg5 | msg7 | msg8) - @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 + # Test: Admin: all messages + messages = self.env['mail.message'].search([('subject', 'like', '_Test')]) + self.assertEqual(messages, msg1 | msg2 | msg3 | msg4 | msg5 | msg6 | msg7 | msg8) - # 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') + # 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) - # prepare an attachment - attachment_id = self.ir_attachment.create(cr, uid, {'datas': 'My attachment'.encode('base64'), 'name': 'doc.txt', 'datas_fname': 'doc.txt'}) + # 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) - # ---------------------------------------- - # CASE1: read - # ---------------------------------------- + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') + 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() + + 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']) + + 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']) + + 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.env['mail.message'].sudo(self.user_employee).download_attachment(self.message.id, self.attachment.id) - # Do: create a new mail.message - message_id = self.mail_message.create(cr, uid, {'body': 'My Body', 'attachment_ids': [(4, 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() - # 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) - # 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}) + 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}) - - 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 + with self.assertRaises(except_orm): + Message.create({'model': 'mail.group', 'res_id': self.group_private.id, 'body': 'Test'}) + + 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) - - # 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') - - # 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') + msg = self.env['mail.message'].browse(msg_id) + msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg_id) + + # 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) + + # 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') - - 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 + msg.set_message_starred(False) + self.assertFalse(msg.starred) + self.assertTrue(msg_emp.starred) + + 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) - - # 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') - - # 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') + msg = self.env['mail.message'].browse(msg_id) + msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg_id) + + # 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) + + # 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') - - 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 + msg.set_message_read(False) + self.assertTrue(msg.to_read) + self.assertFalse(msg_emp.to_read) + + 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) diff --git a/addons/mail/tests/test_mail_template.py b/addons/mail/tests/test_mail_template.py new file mode 100644 index 00000000000..38d132922fa --- /dev/null +++ b/addons/mail/tests/test_mail_template.py @@ -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') + diff --git a/addons/mail/tests/test_message_read.py b/addons/mail/tests/test_message_read.py index fbf30f2ed22..cf7e6fc7e81 100644 --- a/addons/mail/tests/test_message_read.py +++ b/addons/mail/tests/test_message_read.py @@ -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 - - -class test_mail_access_rights(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)] - - # 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] - - # 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') - - # 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') - - # 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') - - # ---------------------------------------- - # 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'] +from openerp.tools import mute_logger + + +class TestMessageRead(TestMail): + + @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] + + # TODO: with_context({'mail_read_set_read': True}) + + 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') + + 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') + + 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') + + 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') diff --git a/addons/mail/tests/test_message_track.py b/addons/mail/tests/test_message_track.py new file mode 100644 index 00000000000..2c8b38d3b45 --- /dev/null +++ b/addons/mail/tests/test_message_track.py @@ -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') diff --git a/addons/portal/tests/__init__.py b/addons/portal/tests/__init__.py index c2e8b115a09..e00314d2c88 100644 --- a/addons/portal/tests/__init__.py +++ b/addons/portal/tests/__init__.py @@ -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 diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py index 6e23ca3d50c..34c031830a9 100644 --- a/addons/portal/tests/test_portal.py +++ b/addons/portal/tests/test_portal.py @@ -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]) - # 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]) - - # 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 + 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() - 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='') + # Do: Chell replies to a Pigs message using the composer + 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() + + @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') - - 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) + 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_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') - - @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') + '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_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']) diff --git a/addons/portal_project/tests/test_access_rights.py b/addons/portal_project/tests/test_access_rights.py index c1b75b07bff..616b081d2f6 100644 --- a/addons/portal_project/tests/test_access_rights.py +++ b/addons/portal_project/tests/test_access_rights.py @@ -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}) -
\ No newline at end of file + 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}) + diff --git a/addons/project/tests/__init__.py b/addons/project/tests/__init__.py index ac890eeab6d..41165dc0957 100644 --- a/addons/project/tests/__init__.py +++ b/addons/project/tests/__init__.py @@ -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 diff --git a/addons/project/tests/test_project_base.py b/addons/project/tests/test_project_base.py index 70f8b59812f..7274a7741e0 100644 --- a/addons/project/tests/test_project_base.py +++ b/addons/project/tests/test_project_base.py @@ -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}) diff --git a/addons/project/tests/test_project_flow.py b/addons/project/tests/test_project_flow.py index a1a457b03ff..76d863330b6 100644 --- a/addons/project/tests/test_project_flow.py +++ b/addons/project/tests/test_project_flow.py @@ -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 - - # ProjectUser: set project as template -> raise - self.assertRaises(AccessError, self.project_project.set_template, cr, user_projectuser_id, [project_pigs_id]) - - # 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') - - # 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_user(self): + self.assertRaises(AccessError, self.project_pigs.sudo(self.user_projectuser).set_template) + + 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') + + # pigs.reset_project() + # self.assertEqual(pigs.state, 'open') + # self.assertEqual(len(pigs.tasks), 2, 'project: reset_project: project tasks should have been set active') + + 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') diff --git a/addons/purchase/tests/test_purchase_to_invoice.py b/addons/purchase/tests/test_purchase_to_invoice.py index 57e323c1d5d..1ae125e609c 100644 --- a/addons/purchase/tests/test_purchase_to_invoice.py +++ b/addons/purchase/tests/test_purchase_to_invoice.py @@ -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') diff --git a/addons/sale/tests/test_sale_to_invoice.py b/addons/sale/tests/test_sale_to_invoice.py index 56ffca64a1c..36ecb6defa8 100644 --- a/addons/sale/tests/test_sale_to_invoice.py +++ b/addons/sale/tests/test_sale_to_invoice.py @@ -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') diff --git a/addons/website_project_issue/tests/test_access_rights.py b/addons/website_project_issue/tests/test_access_rights.py index 3a794fe0c3f..c0d7d6ba88b 100644 --- a/addons/website_project_issue/tests/test_access_rights.py +++ b/addons/website_project_issue/tests/test_access_rights.py @@ -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') |
