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. -# -# 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 . -# -############################################################################## -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. -# -# 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 . -# -############################################################################## + +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 ', + cc='', msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>', + model=None, target_model='mail.group', target_field='name'): + self.assertFalse(self.env[target_model].search([(target_field, '=', subject)])) + mail = template.format(to=to, subject=subject, cc=cc, extra=extra, email_from=email_from, msg_id=msg_id) + self.env['mail.thread'].message_process(model, mail) + return self.env[target_model].search([(target_field, '=', subject)]) def setUp(self): super(TestMail, self).setUp() - cr, uid = self.cr, self.uid - - # Install mock SMTP gateway - test = self + Test = self def build_email(self, *args, **kwargs): - test._build_email_args_list.append(args) - test._build_email_kwargs_list.append(kwargs) + Test._mails_args.append(args) + Test._mails.append(kwargs) return build_email.origin(self, *args, **kwargs) def send_email(self, cr, uid, message, *args, **kwargs): return message['Message-Id'] - self._init_mock_build_email() - self.registry('ir.mail_server')._patch_method('build_email', build_email) - self.registry('ir.mail_server')._patch_method('send_email', send_email) + self.env['ir.mail_server']._patch_method('build_email', build_email) + self.env['ir.mail_server']._patch_method('send_email', send_email) - # Usefull models - self.ir_model = self.registry('ir.model') - self.ir_model_data = self.registry('ir.model.data') - self.ir_attachment = self.registry('ir.attachment') - self.mail_alias = self.registry('mail.alias') - self.mail_thread = self.registry('mail.thread') - self.mail_group = self.registry('mail.group') - self.mail_mail = self.registry('mail.mail') - self.mail_message = self.registry('mail.message') - self.mail_notification = self.registry('mail.notification') - self.mail_followers = self.registry('mail.followers') - self.mail_message_subtype = self.registry('mail.message.subtype') - self.res_users = self.registry('res.users') - self.res_partner = self.registry('res.partner') - - # Find Employee group - group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') - self.group_employee_id = group_employee_ref and group_employee_ref[1] or False - - # Partner Data + # User groups + user_group_employee = self.env.ref('base.group_user') + user_group_portal = self.env.ref('base.group_portal') + user_group_public = self.env.ref('base.group_public') # User Data: employee, noone - self.user_employee_id = self.res_users.create(cr, uid, { + Users = self.env['res.users'].with_context({'no_reset_password': True}) + self.user_employee = Users.create({ 'name': 'Ernest Employee', 'login': 'ernest', 'alias_name': 'ernest', 'email': 'e.e@example.com', 'signature': '--\nErnest', 'notify_email': 'always', - 'groups_id': [(6, 0, [self.group_employee_id])] - }, {'no_reset_password': True}) - self.user_noone_id = self.res_users.create(cr, uid, { + 'groups_id': [(6, 0, [user_group_employee.id])]}) + self.user_employee_2 = Users.create({ + 'name': 'Raoul Grosbedon', + 'login': 'raoul', + 'alias_name': 'raoul', + 'email': 'r.g@example.com', + 'signature': 'SignRaoul', + 'notify_email': 'always', + 'groups_id': [(6, 0, [user_group_employee.id])]}) + self.user_noone = Users.create({ 'name': 'Noemie NoOne', 'login': 'noemie', 'alias_name': 'noemie', 'email': 'n.n@example.com', 'signature': '--\nNoemie', 'notify_email': 'always', - 'groups_id': [(6, 0, [])] - }, {'no_reset_password': True}) - - # Test users to use through the various tests - self.res_users.write(cr, uid, [uid], {'name': 'Administrator'}) - self.user_raoul_id = self.res_users.create(cr, uid, { - 'name': 'Raoul Grosbedon', - 'signature': 'SignRaoul', - 'email': 'raoul@raoul.fr', - 'login': 'raoul', - 'alias_name': 'raoul', - 'groups_id': [(6, 0, [self.group_employee_id])] - }) - self.user_bert_id = self.res_users.create(cr, uid, { + 'groups_id': [(6, 0, [])]}) + self.user_public = Users.create({ 'name': 'Bert Tartignole', - 'signature': 'SignBert', - 'email': 'bert@bert.fr', 'login': 'bert', 'alias_name': 'bert', - 'groups_id': [(6, 0, [])] + 'email': 'b.t@example.com', + 'signature': 'SignBert', + 'notify_email': 'always', + 'groups_id': [(6, 0, [user_group_public.id])]}) + self.user_portal = Users.create({ + 'name': 'Chell Gladys', + 'login': 'chell', + 'alias_name': 'chell', + 'email': 'chell@gladys.portal', + 'signature': 'SignChell', + 'notify_email': 'always', + 'groups_id': [(6, 0, [user_group_portal.id])]}) + self.user_admin = self.env.user + # Update admin + # Set an email address for the user running the tests, used as Sender for outgoing mails + self._company_name = 'TestCompany' + self._admin_name = 'Administrator' + self._admin_email = 'test@localhost' + self.user_admin.write({ + 'email': self._admin_email, + 'name': self._admin_name, + 'signature': 'SignAdmin', + 'notify_email': 'always', + }) + self.user_admin.company_id.write({ + 'name': self._company_name, }) - self.user_raoul = self.res_users.browse(cr, uid, self.user_raoul_id) - self.user_bert = self.res_users.browse(cr, uid, self.user_bert_id) - self.user_admin = self.res_users.browse(cr, uid, uid) - self.partner_admin_id = self.user_admin.partner_id.id - self.partner_raoul_id = self.user_raoul.partner_id.id - self.partner_bert_id = self.user_bert.partner_id.id - # Test 'pigs' group to use through the various tests - self.group_pigs_id = self.mail_group.create( - cr, uid, - {'name': 'Pigs', 'description': 'Fans of Pigs, unite !', 'alias_name': 'group+pigs'}, - {'mail_create_nolog': True} - ) - self.group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id) - # Test mail.group: public to provide access to everyone - self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) - # Test mail.group: private to restrict access - self.group_priv_id = self.mail_group.create(cr, uid, {'name': 'Private', 'public': 'private'}) + # Test Data for Partners + self.partner_1 = self.env['res.partner'].create({ + 'name': 'Valid Lelitre', + 'email': 'valid.lelitre@agrolait.com', + 'notify_email': 'always'}) + self.partner_2 = self.env['res.partner'].create({ + 'name': 'Valid Poilvache', + 'email': 'valid.other@gmail.com', + 'notify_email': 'always'}) + + # Create test groups without followers and messages by default + TestMailGroup = self.env['mail.group'].with_context({ + 'mail_create_nolog': True, + 'mail_create_nosubscribe': True + }) + # Pigs: base group for tests + self.group_pigs = TestMailGroup.create({ + 'name': 'Pigs', + 'description': 'Fans of Pigs, unite !', + 'public': 'groups', + 'group_public_id': user_group_employee.id, + 'alias_name': 'pigs', + 'alias_contact': 'followers'} + ).with_context({'mail_create_nosubscribe': False}) + # Jobs: public group + self.group_public = TestMailGroup.create({ + 'name': 'Jobs', + 'description': 'NotFalse', + 'public': 'public', + 'alias_name': 'public', + 'alias_contact': 'everyone'} + ).with_context({'mail_create_nosubscribe': False}) + # Private: private group + self.group_private = TestMailGroup.create({ + 'name': 'Private', + 'public': 'private'} + ).with_context({'mail_create_nosubscribe': False}) + # Portal: group-based group using portal group + self.group_portal = TestMailGroup.create({ + 'name': 'PigsPortal', + 'public': 'groups', + 'group_public_id': user_group_portal.id} + ).with_context({'mail_create_nosubscribe': False}) + + # groups@.. will cause the creation of new mail groups + self.mail_group_model = self.env['ir.model'].search([('model', '=', 'mail.group')], limit=1) + self.alias = self.env['mail.alias'].create({ + 'alias_name': 'groups', + 'alias_user_id': False, + 'alias_model_id': self.mail_group_model.id, + 'alias_contact': 'everyone'}) + + # Set a first message on public group to test update and hierarchy + self.fake_email = self.env['mail.message'].create({ + 'model': 'mail.group', + 'res_id': self.group_public.id, + 'subject': 'Public Discussion', + 'type': 'email', + 'author_id': self.partner_1.id, + 'message_id': '<123456-openerp-%s-mail.group@%s>' % (self.group_public.id, socket.gethostname()), + }) + + self._init_mock_build_email() def tearDown(self): # Remove mocks - self.registry('ir.mail_server')._revert_method('build_email') - self.registry('ir.mail_server')._revert_method('send_email') + self.env['ir.mail_server']._revert_method('build_email') + self.env['ir.mail_server']._revert_method('send_email') super(TestMail, self).tearDown() 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. -# -# 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 . -# -############################################################################## 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. -# -# 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 . -# -############################################################################## 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': '

Dear ${object.name}, your parent is ${object.parent_id and object.parent_id.name or "False"}

', }) - - 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, '

Dear TestingPartner, your parent is False

', '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. -# -# 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 . -# -############################################################################## - -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': '

Dummy body

'}, - {'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, '

Dummy body

', '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, '

${object.description}

', '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 ', - '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 '], - ['Raoul Grosbedon '], ['Bert Tartignole ']] - 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. -# -# 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 . -# -############################################################################## -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 +from openerp.tools import mute_logger -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") +class TestMailFeatures(TestMail): - 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") + def test_alias_setup(self): + Users = self.env['res.users'].with_context({'no_reset_password': True}) - 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') + 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") - 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 + 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") - # 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}) + 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') - # 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') + 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) - # 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') + 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) - # 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, + 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 + @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=[]) - # -------------------------------------------------- - # 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, { + 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 = '

Pigs rules

' - _body2 = 'Pigs rocks' + 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 = '

Test Body

', 'Test Body' + _subject = 'Test Subject' _attachments = [ ('List1', 'My first attachment'), ('List2', 'My second attachment') ] + # 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) - # -------------------------------------------------- - # CASE1: post comment + partners + attachments - # -------------------------------------------------- + # 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) - # 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" !ù $%-'}) + 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) - # 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)), + # 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') + # notifications + self.assertFalse(self.env['mail.mail'].search([('mail_message_id', '=', msg.message_id)]), + 'message_post: mail.mail notifications should have been auto-deleted') - # 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') + # 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)) - # 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!') + @mute_logger('openerp.addons.mail.mail_mail') + def test_post_answer(self): + _body = '

Test Body

' + _subject = 'Test Subject' - # Test: notifications emails: to a and b, c is email only, r is author - test_emailto = ['Administrator ', 'Bert Tartopoils '] - # test_emailto = ['"Followers of -Pigs-" ', '"Followers of -Pigs-" '] - 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 ', - '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\\" !ù $%-" ', - '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('

', 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') + # 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) - # 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') + 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) - # Data: Pigs name back to normal - self.mail_group.write(cr, uid, [self.group_pigs_id], {'name': 'Pigs'}) + self.assertEqual(parent_msg.notified_partner_ids, self.env['res.partner']) - # -------------------------------------------------- - # CASE2: reply + parent_id + parent notification - # -------------------------------------------------- + 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) - # 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) + 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) - # 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 + self.assertEqual(new_msg.parent_id.id, parent_msg_id, 'message_post: flatten error') + self.assertFalse(new_msg.notified_partner_ids) - # 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') + @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': '

Test Body

', + '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) - # 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!') + composer.send_mail() + message = self.group_pigs.message_ids[0] - # Test: emails send by server (to a, b, c, d) - test_emailto = [u'Administrator ', u'Bert Tartopoils ', u'Carine Poilvache ', u'D\xe9d\xe9 Grosbedon '] - # test_emailto = [u'"Followers of Pigs" ', u'"Followers of Pigs" ', u'"Followers of Pigs" ', u'"Followers of Pigs" '] - # 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 ', - '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" ', 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('

', 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') + 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({}) - # 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') + 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) - # 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') + # TODO: test attachments ? - 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') + @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': '

${object.description}

', + '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() - # -------------------------------------------------- - # 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 rule' - _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, '

%s

' % _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] - }) # 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] + # 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, '

%s

' % self.group_pigs.description) - # 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') + # 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, '

%s

' % self.group_public.description) - # 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, '

%s

' % 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, '

%s

' % 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') + # # 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') + # 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') - # 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) + @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() - # 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(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. -# -# 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 . -# -############################################################################## from openerp.addons.mail.tests.common import TestMail from openerp.tools import mute_logger @@ -25,6 +6,7 @@ import socket MAIL_TEMPLATE = """Return-Path: To: {to} +cc: {cc} Received: by mail1.openerp.com (Postfix, from userid 10002) id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST) From: {email_from} @@ -88,7 +70,7 @@ Delivered-To: raoul@grosbedon.fr Received: by mail1.grosbedon.com (Postfix, from userid 10002) id E8166BFACA; Fri, 23 Aug 2013 13:18:01 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail1.grosbedon.com -X-Spam-Level: +X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_LOW autolearn=unavailable version=3.3.1 Received: from mail-ie0-f173.google.com (mail-ie0-f173.google.com [209.85.223.173]) @@ -125,7 +107,7 @@ Content-Type: text/plain; charset=ISO-8859-1 Should create a multipart/mixed: from gmail, *bold*, with attachment. --- +-- Marcel Boitempoils. --089e01536c4ed4d16d04e49b8e94 @@ -191,548 +173,385 @@ Content-Type: text/html; --Apple-Mail=_9331E12B-8BD2-4EC7-B53E-01F3FBEC9227-- """ + class TestMailgateway(TestMail): - def test_00_message_parse(self): - """ Testing incoming emails parsing """ - cr, uid = self.cr, self.uid - - res = self.mail_thread.message_parse(cr, uid, MAIL_TEMPLATE_PLAINTEXT) - self.assertIn('Please call me as soon as possible this afternoon!', res.get('body', ''), + @mute_logger('openerp.addons.mail.mail_thread') + def test_message_parse(self): + """ Test parsing of various scenarios of incoming emails """ + res = self.env['mail.thread'].message_parse(MAIL_TEMPLATE_PLAINTEXT) + self.assertIn('Please call me as soon as possible this afternoon!', + res.get('body', ''), 'message_parse: missing text in text/plain body after parsing') - res = self.mail_thread.message_parse(cr, uid, MAIL_TEMPLATE) - self.assertIn('

Please call me as soon as possible this afternoon!

', res.get('body', ''), + res = self.env['mail.thread'].message_parse(MAIL_TEMPLATE) + self.assertIn('

Please call me as soon as possible this afternoon!

', + 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('
Should create a multipart/mixed: from gmail, bold, with attachment.

', res.get('body', ''), + self.assertIn('
Should create a multipart/mixed: from gmail, bold, with attachment.

', + res.get('body', ''), 'message_parse: html version should be in body after parsing multipart/mixed') - res = self.mail_thread.message_parse(cr, uid, MAIL_MULTIPART_MIXED_TWO) - self.assertNotIn('First and second part', res.get('body', ''), + res = self.env['mail.thread'].message_parse(MAIL_MULTIPART_MIXED_TWO) + self.assertNotIn('First and second part', + res.get('body', ''), 'message_parse: text version should not be in body after parsing multipart/mixed') - self.assertIn('First part', res.get('body', ''), + self.assertIn('First part', + res.get('body', ''), 'message_parse: first part of the html version should be in body after parsing multipart/mixed') - self.assertIn('Second part', res.get('body', ''), + self.assertIn('Second part', + res.get('body', ''), 'message_parse: second part of the html version should be in body after parsing multipart/mixed') @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') - def test_10_message_process(self): - """ Testing incoming emails processing. """ - cr, uid, user_raoul = self.cr, self.uid, self.user_raoul + def test_message_process_alias_basic(self): + """ Incoming email on an alias creating a new record + message_new + message details """ + new_groups = self.format_and_process(MAIL_TEMPLATE, subject='My Frogs', to='groups@example.com, other@gmail.com') - def format_and_process(template, to='groups@example.com, other@gmail.com', subject='Frogs', - extra='', email_from='Sylvie Lelitre ', - msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>', - model=None): - self.assertEqual(self.mail_group.search(cr, uid, [('name', '=', subject)]), []) - mail = template.format(to=to, subject=subject, extra=extra, email_from=email_from, msg_id=msg_id) - self.mail_thread.message_process(cr, uid, model, mail) - return self.mail_group.search(cr, uid, [('name', '=', subject)]) - - # -------------------------------------------------- - # Data creation - # -------------------------------------------------- - - # groups@.. will cause the creation of new mail groups - self.mail_group_model_id = self.ir_model.search(cr, uid, [('model', '=', 'mail.group')])[0] - alias_id = self.mail_alias.create(cr, uid, { - 'alias_name': 'groups', - 'alias_user_id': False, - 'alias_model_id': self.mail_group_model_id, - 'alias_parent_model_id': self.mail_group_model_id, - 'alias_parent_thread_id': self.group_pigs_id, - 'alias_contact': 'everyone'}) - - # -------------------------------------------------- - # Test1: new record creation - # -------------------------------------------------- - - # Do: incoming mail from an unknown partner on an alias creates a new mail_group "frogs" - self._init_mock_build_email() - frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com') - sent_emails = self._build_email_kwargs_list # Test: one group created by mailgateway administrator - self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created') - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - res = self.mail_group.get_metadata(cr, uid, [frog_group.id])[0].get('create_uid') or [None] - self.assertEqual(res[0], uid, - 'message_process: group should have been created by uid as alias_user__id is False on the alias') + self.assertEqual(len(new_groups), 1, 'message_process: a new mail.group should have been created') + res = new_groups.get_metadata()[0].get('create_uid') or [None] + self.assertEqual(res[0], self.env.uid, + 'message_process: group should have been created by uid as alias_user_id is False on the alias') + # Test: one message that is the incoming email - self.assertEqual(len(frog_group.message_ids), 1, + self.assertEqual(len(new_groups.message_ids), 1, 'message_process: newly created group should have the incoming email in message_ids') - msg = frog_group.message_ids[0] - self.assertEqual('Frogs', msg.subject, + msg = new_groups.message_ids[0] + self.assertEqual(msg.subject, 'My Frogs', 'message_process: newly created group should have the incoming email as first message') self.assertIn('Please call me as soon as possible this afternoon!', msg.body, 'message_process: newly created group should have the incoming email as first message') - self.assertEqual('email', msg.type, + self.assertEqual(msg.type, 'email', 'message_process: newly created group should have an email as first message') - self.assertEqual('Discussions', msg.subtype_id.name, + self.assertEqual(msg.subtype_id, self.env.ref('mail.mt_comment'), 'message_process: newly created group should not have a log first message but an email') - # Test: message: unknown email address -> message has email_from, not author_id - self.assertFalse(msg.author_id, - 'message_process: message on created group should not have an author_id') - self.assertIn('test.sylvie.lelitre@agrolait.com', msg.email_from, - 'message_process: message on created group should have an email_from') - # Test: followers: nobody - self.assertEqual(len(frog_group.message_follower_ids), 0, 'message_process: newly create group should not have any follower') - # Test: sent emails: no-one - self.assertEqual(len(sent_emails), 0, - 'message_process: should create emails without any follower added') - # Data: unlink group - frog_group.unlink() - # Do: incoming email from an unknown partner on a Partners only alias -> bounce - self._init_mock_build_email() - self.mail_alias.write(cr, uid, [alias_id], {'alias_contact': 'partners'}) - frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other2@gmail.com') - # Test: no group created - self.assertTrue(len(frog_groups) == 0) - # Test: email bounced - sent_emails = self._build_email_kwargs_list - self.assertEqual(len(sent_emails), 1, + # Test: sent emails: no-one + self.assertEqual(len(self._mails), 0, + 'message_process: should create emails without any follower added') + + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_alias_user_id(self): + """ Test alias ownership """ + self.alias.write({'alias_user_id': self.user_employee.id}) + new_groups = self.format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com') + + # Test: one group created by mailgateway administrator + self.assertEqual(len(new_groups), 1, 'message_process: a new mail.group should have been created') + res = new_groups.get_metadata()[0].get('create_uid') or [None] + self.assertEqual(res[0], self.user_employee.id, + 'message_process: group should have been created by alias_user_id') + + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_email_email_from(self): + """ Incoming email: not recognized author: email_from, no author_id, no followers """ + new_groups = self.format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com') + + self.assertFalse(new_groups.message_ids[0].author_id, + 'message_process: unrecognized email -> no author_id') + self.assertIn('test.sylvie.lelitre@agrolait.com', new_groups.message_ids[0].email_from, + 'message_process: unrecognized email -> email_from') + + self.assertEqual(len(new_groups.message_follower_ids), 0, + 'message_process: newly create group should not have any follower') + + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_email_author(self): + """ Incoming email: recognized author: email_from, author_id, added as follower """ + new_groups = self.format_and_process(MAIL_TEMPLATE, email_from='Valid Lelitre ', 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 ', 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 ', 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 ', 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 ', msg.email_from, - 'message_process: message on created group should have have an email_from') - # Test: author (not recipient and not Raoul (as alias owner)) added as follower - frog_follower_ids = set([p.id for p in frog_group.message_follower_ids]) - self.assertEqual(frog_follower_ids, set([p1id]), - 'message_process: newly created group should have 1 follower (author, not creator, not recipients)') - # Test: sent emails: no-one, no bounce effet - sent_emails = self._build_email_kwargs_list - self.assertEqual(len(sent_emails), 0, - 'message_process: should not bounce incoming emails') - # Data: unlink group - frog_group.unlink() - # Do: incoming email from a not follower Partner on a Followers only alias -> bounce - self._init_mock_build_email() - self.mail_alias.write(cr, uid, [alias_id], {'alias_user_id': False, 'alias_contact': 'followers'}) - frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other5@gmail.com') - # Test: no group created - self.assertTrue(len(frog_groups) == 0) - # Test: email bounced - sent_emails = self._build_email_kwargs_list - self.assertEqual(len(sent_emails), 1, - 'message_process: incoming email on Partners alias should send a bounce email') + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_alias_followers(self): + """ Incoming email from a parent document follower on a Followers only alias -> ok """ + self.alias.write({ + 'alias_contact': 'followers', + 'alias_parent_model_id': self.mail_group_model.id, + 'alias_parent_thread_id': self.group_pigs.id}) + self.group_pigs.message_subscribe(partner_ids=[self.partner_1.id]) + new_groups = self.format_and_process(MAIL_TEMPLATE, email_from='Valid Lelitre ', to='groups@example.com, other6@gmail.com') - # Do: incoming email from a parent document follower on a Followers only alias -> ok - self._init_mock_build_email() - self.mail_group.message_subscribe(cr, uid, [self.group_pigs_id], [p1id]) - frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other6@gmail.com') # Test: one group created by Raoul (or Sylvie maybe, if we implement it) - self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created') - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: one message that is the incoming email - self.assertEqual(len(frog_group.message_ids), 1, - 'message_process: newly created group should have the incoming email in message_ids') - # Test: author (and not recipient) added as follower - frog_follower_ids = set([p.id for p in frog_group.message_follower_ids]) - self.assertEqual(frog_follower_ids, set([p1id]), - 'message_process: newly created group should have 1 follower (author, not creator, not recipients)') - # Test: sent emails: no-one, no bounce effet - sent_emails = self._build_email_kwargs_list - self.assertEqual(len(sent_emails), 0, - 'message_process: should not bounce incoming emails') + self.assertEqual(len(new_groups), 1, 'message_process: a new mail.group should have been created') - # -------------------------------------------------- - # Test2: update-like alias - # -------------------------------------------------- + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models', 'openerp.addons.mail.mail_mail') + def test_message_process_alias_update(self): + """ Incoming email update discussion + notification email """ + self.alias.write({'alias_force_thread_id': self.group_public.id}) - # Do: Pigs alias is restricted, should bounce - self._init_mock_build_email() - self.mail_group.write(cr, uid, [frog_group.id], {'alias_name': 'frogs', 'alias_contact': 'followers', 'alias_force_thread_id': frog_group.id}) - frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com', - msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>', - to='frogs@example.com>', subject='Re: news') - # Test: no group 'Re: news' created, still only 1 Frogs group - self.assertEqual(len(frog_groups), 0, + self.group_public.message_subscribe(partner_ids=[self.partner_1.id]) + new_groups = self.format_and_process( + MAIL_TEMPLATE, email_from='valid.other@gmail.com', + msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>', + to='groups@example.com>', subject='Re: cats') + + # Test: no new group + new message + self.assertEqual(len(new_groups), 0, 'message_process: reply on Frogs should not have created a new group with new subject') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - self.assertEqual(len(frog_groups), 1, - 'message_process: reply on Frogs should not have created a duplicate group with old subject') - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: email bounced - sent_emails = self._build_email_kwargs_list - self.assertEqual(len(sent_emails), 1, - 'message_process: incoming email on Followers alias should send a bounce email') - self.assertIn('Re: news', sent_emails[0].get('subject'), - 'message_process: bounce email on Followers alias should contain the original subject') - - # Do: Pigs alias is restricted, should accept Followers - self._init_mock_build_email() - self.mail_group.message_subscribe(cr, uid, [frog_group.id], [p2id]) - frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com', - msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>', - to='frogs@example.com>', subject='Re: cats') - # Test: no group 'Re: news' created, still only 1 Frogs group - self.assertEqual(len(frog_groups), 0, - 'message_process: reply on Frogs should not have created a new group with new subject') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - self.assertEqual(len(frog_groups), 1, - 'message_process: reply on Frogs should not have created a duplicate group with old subject') - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: one new message - self.assertEqual(len(frog_group.message_ids), 2, 'message_process: group should contain 2 messages after reply') - # Test: sent emails: 1 (Sylvie copy of the incoming email, but no bounce) - sent_emails = self._build_email_kwargs_list - self.assertEqual(len(sent_emails), 1, + self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: group should contain one new message') + # Test: sent emails: 1 (Sylvie copy of the incoming email) + self.assertEqual(len(self._mails), 1, 'message_process: one email should have been generated') - self.assertIn('test.sylvie.lelitre@agrolait.com', sent_emails[0].get('email_to')[0], + self.assertIn('valid.lelitre@agrolait.com', self._mails[0].get('email_to')[0], 'message_process: email should be sent to Sylvie') - self.mail_group.message_unsubscribe(cr, uid, [frog_group.id], [p2id]) - - # -------------------------------------------------- - # Test3: discussion and replies - # -------------------------------------------------- - - # Do: even with a wrong destination, a reply should end up in the correct thread - frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com', - msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>', - to='erroneous@example.com>', subject='Re: news', - extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>\n') - # Test: no group 'Re: news' created, still only 1 Frogs group - self.assertEqual(len(frog_groups), 0, - 'message_process: reply on Frogs should not have created a new group with new subject') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - self.assertEqual(len(frog_groups), 1, - 'message_process: reply on Frogs should not have created a duplicate group with old subject') - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: one new message - self.assertEqual(len(frog_group.message_ids), 3, 'message_process: group should contain 3 messages after reply') # Test: author (and not recipient) added as follower - frog_follower_ids = set([p.id for p in frog_group.message_follower_ids]) - self.assertEqual(frog_follower_ids, set([p1id, p2id]), + self.assertEqual(self.group_public.message_follower_ids, self.partner_1 | self.partner_2, 'message_process: after reply, group should have 2 followers') - # Do: incoming email with ref holding model / res_id but that does not match any message in the thread: must raise since OpenERP saas-3 + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_in_reply_to(self): + """ Incoming email using in-rely-to should go into the right destination event with a wrong destination """ + self.format_and_process( + MAIL_TEMPLATE, email_from='valid.other@gmail.com', + msg_id='<1198923581.41972151344608186800.JavaMail.diff1@agrolait.com>', + to='erroneous@example.com>', subject='Re: news', + extra='In-Reply-To: %s\n' % self.fake_email.message_id) + + self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: group should contain one new message') + self.assertEqual(len(self.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one') + + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_references(self): + """ Incoming email using in-rely-to should go into the right destination event with a wrong destination """ + self.format_and_process( + MAIL_TEMPLATE, to='erroneous@example.com', + extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % self.fake_email.message_id, + msg_id='<1198923581.41972151344608186800.JavaMail.4@agrolait.com>') + + self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: group should contain one new message') + self.assertEqual(len(self.fake_email.child_ids), 1, 'message_process: new message should be children of the existing one') + + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_model_res_id(self): + """ Incoming email with ref holding model / res_id but that does not match any message in the thread: must raise since OpenERP saas-3 """ self.assertRaises(ValueError, - format_and_process, - MAIL_TEMPLATE, email_from='other5@gmail.com', + self.format_and_process, + MAIL_TEMPLATE, email_from='valid.lelitre@agrolait.com', to='noone@example.com', subject='spam', - extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>' % frog_group.id, - msg_id='<1.1.JavaMail.new@agrolait.com>') + extra='In-Reply-To: <12321321-openerp-%d-mail.group@%s>' % (self.group_public.id, socket.gethostname()), + msg_id='<1198923581.41972151344608186802.JavaMail.diff1@agrolait.com>') - # When 6.1 messages are present, compat mode is available - # Create a fake 6.1 message - tmp_msg_id = self.mail_message.create(cr, uid, {'model': 'mail.group', 'res_id': frog_group.id}) - self.mail_message.write(cr, uid, [tmp_msg_id], {'message_id': False}) + # when 6.1 messages are present, compat mode is available + self.fake_email.write({'message_id': False}) # Do: compat mode accepts partial-matching emails - frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other5@gmail.com', - msg_id='<1.2.JavaMail.new@agrolait.com>', - to='noone@example.com>', subject='spam', - extra='In-Reply-To: <12321321-openerp-%d-mail.group@%s>' % (frog_group.id, socket.gethostname())) - self.mail_message.unlink(cr, uid, [tmp_msg_id]) - # Test: no group 'Re: news' created, still only 1 Frogs group - self.assertEqual(len(frog_groups), 0, - 'message_process: reply on Frogs should not have created a new group with new subject') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - self.assertEqual(len(frog_groups), 1, - 'message_process: reply on Frogs should not have created a duplicate group with old subject') - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: one new message - self.assertEqual(len(frog_group.message_ids), 4, 'message_process: group should contain 4 messages after reply') + frog_groups = self.format_and_process( + MAIL_TEMPLATE, email_from='other5@gmail.com', + msg_id='<1.2.JavaMail.new@agrolait.com>', + to='noone@example.com>', subject='spam', + extra='In-Reply-To: <12321321-openerp-%d-mail.group@%s>' % (self.group_public.id, socket.gethostname())) - # 6.1 compat mode should not work if hostname does not match! - tmp_msg_id = self.mail_message.create(cr, uid, {'model': 'mail.group', 'res_id': frog_group.id}) - self.mail_message.write(cr, uid, [tmp_msg_id], {'message_id': False}) + # 3''. 6.1 compat mode should not work if hostname does not match! self.assertRaises(ValueError, - format_and_process, + self.format_and_process, MAIL_TEMPLATE, email_from='other5@gmail.com', msg_id='<1.3.JavaMail.new@agrolait.com>', to='noone@example.com>', subject='spam', - extra='In-Reply-To: <12321321-openerp-%d-mail.group@neighbor.com>' % frog_group.id) - self.mail_message.unlink(cr, uid, [tmp_msg_id]) + extra='In-Reply-To: <12321321-openerp-%d-mail.group@neighbor.com>' % frog_groups.id) + # 4. Subject contains [] + model passed to message+process -> only attached to group, but not to mail (not in msg1.child_ids) + self.format_and_process( + MAIL_TEMPLATE, + to='erroneous@example.com', email_from='other6@gmail.com', + extra='', subject='Re: [%s] 1' % self.group_public.id, model='mail.group', + msg_id='<1198923581.41972151344608186803.JavaMail.5@agrolait.com>') + + # Test created messages + self.assertEqual(len(self.group_public.message_ids), 3, 'message_process: group should contain 6 messages') + self.assertEqual(len(self.group_public.message_ids[0].child_ids), 0, 'message_process: msg1 should not have children') + + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_duplicate(self): + """ Duplicate emails (same message_id) are not processed """ + self.alias.write({'alias_force_thread_id': self.group_public.id,}) + + # Post a base message + frog_groups = self.format_and_process( + MAIL_TEMPLATE, email_from='valid.other@gmail.com', subject='Re: super cats', + msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>') # Do: due to some issue, same email goes back into the mailgateway - frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com', - msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>', - subject='Re: news', extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>\n') + frog_groups = self.format_and_process( + MAIL_TEMPLATE, email_from='other4@gmail.com', subject='Re: news', + msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>', + extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>\n') + # Test: no group 'Re: news' created, still only 1 Frogs group self.assertEqual(len(frog_groups), 0, 'message_process: reply on Frogs should not have created a new group with new subject') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - self.assertEqual(len(frog_groups), 1, - 'message_process: reply on Frogs should not have created a duplicate group with old subject') - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) + # Test: no new message - self.assertEqual(len(frog_group.message_ids), 4, 'message_process: message with already existing message_id should not have been duplicated') + self.assertEqual(len(self.group_public.message_ids), 2, 'message_process: message with already existing message_id should not have been duplicated') # Test: message_id is still unique - msg_ids = self.mail_message.search(cr, uid, [('message_id', 'ilike', '<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>')]) - self.assertEqual(len(msg_ids), 1, + no_of_msg = self.env['mail.message'].search_count([('message_id', 'ilike', '<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>')]) + self.assertEqual(no_of_msg, 1, 'message_process: message with already existing message_id should not have been duplicated') - # -------------------------------------------------- - # Test4: email_from and partner finding - # -------------------------------------------------- + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_partner_find(self): + """ Finding the partner based on email, based on partner / user / follower """ + from_1 = self.env['res.partner'].create({'name': 'A', 'email': 'from.test@example.com'}) - # Data: extra partner with Raoul's email -> test the 'better author finding' - extra_partner_id = self.res_partner.create(cr, uid, {'name': 'A-Raoul', 'email': 'test_raoul@email.com'}) + self.format_and_process(MAIL_TEMPLATE, to='public@example.com', msg_id='<1>', email_from='Brice Denisse ') + self.assertEqual(self.group_public.message_ids[0].author_id, from_1, 'message_process: email_from -> author_id wrong') + self.group_public.message_unsubscribe(partner_ids=[from_1.id]) - # Do: post a new message, with a known partner -> duplicate emails -> partner - format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik ', - subject='Re: news (2)', - msg_id='<1198923581.41972151344608186760.JavaMail.new1@agrolait.com>', - extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: author is A-Raoul (only existing) - self.assertEqual(frog_group.message_ids[0].author_id.id, extra_partner_id, - 'message_process: email_from -> author_id wrong') + from_2 = self.env['res.users'].with_context({'no_reset_password': True}).create({'name': 'B', 'login': 'B', 'email': 'from.test@example.com'}) - # Do: post a new message with a non-existant email that is a substring of a partner email - format_and_process(MAIL_TEMPLATE, email_from='Not really Lombrik Lubrik ', - subject='Re: news (2)', - msg_id='', - extra='In-Reply-To: <1198923581.41972151344608186760.JavaMail@agrolait.com>\n') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: author must not be set, otherwise the system is confusing different users - self.assertFalse(frog_group.message_ids[0].author_id, 'message_process: email_from -> mismatching author_id') + self.format_and_process(MAIL_TEMPLATE, to='public@example.com', msg_id='<2>', email_from='Brice Denisse ') + self.assertEqual(self.group_public.message_ids[0].author_id, from_2.partner_id, 'message_process: email_from -> author_id wrong') + self.group_public.message_unsubscribe(partner_ids=[from_2.id]) - # Do: post a new message, with a known partner -> duplicate emails -> user - frog_group.message_unsubscribe([extra_partner_id]) - self.res_users.write(cr, uid, self.user_raoul_id, {'email': 'test_raoul@email.com'}) - format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik ', - to='groups@example.com', subject='Re: news (3)', - msg_id='<1198923581.41972151344608186760.JavaMail.new2@agrolait.com>', - extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: author is Raoul (user), not A-Raoul - self.assertEqual(frog_group.message_ids[0].author_id.id, self.partner_raoul_id, - 'message_process: email_from -> author_id wrong') + from_3 = self.env['res.partner'].create({'name': 'C', 'email': 'from.test@example.com'}) + self.group_public.message_subscribe(partner_ids=[from_3.id]) - # Do: post a new message, with a known partner -> duplicate emails -> partner because is follower - frog_group.message_unsubscribe([self.partner_raoul_id]) - frog_group.message_subscribe([extra_partner_id]) - raoul_email = self.user_raoul.email - self.res_users.write(cr, uid, self.user_raoul_id, {'email': 'test_raoul@email.com'}) - format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik ', - to='groups@example.com', subject='Re: news (3)', - msg_id='<1198923581.41972151344608186760.JavaMail.new3@agrolait.com>', - extra='In-Reply-To: <1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>') - frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')]) - frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - # Test: author is Raoul (user), not A-Raoul - self.assertEqual(frog_group.message_ids[0].author_id.id, extra_partner_id, - 'message_process: email_from -> author_id wrong') + self.format_and_process(MAIL_TEMPLATE, to='public@example.com', msg_id='<3>', email_from='Brice Denisse ') + self.assertEqual(self.group_public.message_ids[0].author_id, from_3, 'message_process: email_from -> author_id wrong') - self.res_users.write(cr, uid, self.user_raoul_id, {'email': raoul_email}) - - # -------------------------------------------------- - # Test5: misc gateway features - # -------------------------------------------------- - - # Do: incoming email with model that does not accepts incoming emails must raise + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_crash_wrong_model(self): + """ Incoming email with model that does not accepts incoming emails must raise """ self.assertRaises(ValueError, - format_and_process, + self.format_and_process, MAIL_TEMPLATE, to='noone@example.com', subject='spam', extra='', model='res.country', msg_id='<1198923581.41972151344608186760.JavaMail.new4@agrolait.com>') - # Do: incoming email without model and without alias must raise + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_crash_no_data(self): + """ Incoming email without model and without alias must raise """ self.assertRaises(ValueError, - format_and_process, + self.format_and_process, MAIL_TEMPLATE, to='noone@example.com', subject='spam', extra='', msg_id='<1198923581.41972151344608186760.JavaMail.new5@agrolait.com>') - # Do: incoming email with model that accepting incoming emails as fallback - frog_groups = format_and_process(MAIL_TEMPLATE, - to='noone@example.com', - subject='Spammy', extra='', model='mail.group', - msg_id='<1198923581.41972151344608186760.JavaMail.new6@agrolait.com>') + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') + def test_message_process_fallback(self): + """ Incoming email with model that accepting incoming emails as fallback """ + frog_groups = self.format_and_process( + MAIL_TEMPLATE, to='noone@example.com', subject='Spammy', extra='', model='mail.group', + msg_id='<1198923581.41972151344608186760.JavaMail.new6@agrolait.com>') self.assertEqual(len(frog_groups), 1, 'message_process: erroneous email but with a fallback model should have created a new mail.group') - # Do: incoming email in plaintext should be stored as html - frog_groups = format_and_process(MAIL_TEMPLATE_PLAINTEXT, - to='groups@example.com', subject='Frogs Return', extra='', - msg_id='') - # 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='') 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('
\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n
', 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 , other@gmail.com', subject='Re: 1', - extra='', email_from='Sylvie Lelitre ', - 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 ', - 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 [] + 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 , other@gmail.com', subject='Re: 1', - extra='', email_from='Sylvie Lelitre ', - 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='') - 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='') # Test: last mail_message created - msg2_id = self.mail_message.search(cr, uid, [], limit=1)[0] - + msg = self.env['mail.message'].search([], limit=1) # Test: message recipients - msg = self.mail_message.browse(cr, uid, msg2_id) - msg_pids = [p.id for p in msg.partner_ids] - msg_nids = [p.id for p in msg.notified_partner_ids] - test_pids = [self.partner_admin_id, self.partner_raoul_id] - test_nids = test_pids - self.assertEqual(msg.author_id.id, self.partner_bert_id, + self.assertEqual(msg.author_id, self.partner_1, 'message_post: private discussion: wrong author through mailgatewya based on email') - self.assertEqual(set(msg_pids), set(test_pids), + self.assertEqual(msg.partner_ids, self.user_employee.partner_id | self.user_employee_2.partner_id, 'message_post: private discussion: incorrect recipients when replying') - self.assertEqual(set(msg_nids), set(test_nids), + self.assertEqual(msg.notified_partner_ids, self.user_employee.partner_id | self.user_employee_2.partner_id, 'message_post: private discussion: incorrect notified recipients when replying') # Do: Bert replies through chatter (is a customer) - msg3_id = self.mail_thread.message_post( - cr, uid, False, - author_id=self.partner_bert_id, - parent_id=msg1_id, subtype='mail.mt_comment') + msg3_id = self.env['mail.thread'].message_post(author_id=self.partner_1.id, parent_id=msg1_id, subtype='mail.mt_comment') # Test: message recipients - msg = self.mail_message.browse(cr, uid, msg3_id) - msg_pids = [p.id for p in msg.partner_ids] - msg_nids = [p.id for p in msg.notified_partner_ids] - test_pids = [self.partner_admin_id, self.partner_raoul_id] - test_nids = test_pids - self.assertEqual(set(msg_pids), set(test_pids), + msg = self.env['mail.message'].browse(msg3_id) + self.assertEqual(msg.partner_ids, self.user_employee.partner_id | self.user_employee_2.partner_id, 'message_post: private discussion: incorrect recipients when replying') - self.assertEqual(set(msg_nids), set(test_nids), - 'message_post: private discussion: incorrect notified recipients when replying') - - # Do: Administrator replies - msg3_id = self.mail_thread.message_post(cr, uid, False, parent_id=msg3_id, subtype='mail.mt_comment') - - # Test: message recipients - msg = self.mail_message.browse(cr, uid, msg3_id) - msg_pids = [p.id for p in msg.partner_ids] - msg_nids = [p.id for p in msg.notified_partner_ids] - test_pids = [self.partner_bert_id, self.partner_raoul_id] - test_nids = test_pids - self.assertEqual(set(msg_pids), set(test_pids), - 'message_post: private discussion: incorrect recipients when replying') - self.assertEqual(set(msg_nids), set(test_nids), + self.assertEqual(msg.notified_partner_ids, self.user_employee.partner_id | self.user_employee_2.partner_id, 'message_post: private discussion: incorrect notified recipients when replying') 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. -# -# 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 . -# -############################################################################## from openerp.addons.mail.tests.common import TestMail from openerp.exceptions import AccessError +from openerp.exceptions import except_orm from openerp.tools import mute_logger class TestMailGroup(TestMail): @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') - def test_00_mail_group_access_rights(self): - """ Testing mail_group access rights and basic mail_thread features """ - cr, uid, user_noone_id, user_employee_id = self.cr, self.uid, self.user_noone_id, self.user_employee_id + def test_access_rights_public(self): + # Read public group -> ok + self.group_public.sudo(self.user_public).read() - # Do: Bert reads Jobs -> ok, public - self.mail_group.read(cr, user_noone_id, [self.group_jobs_id]) - # Do: Bert read Pigs -> ko, restricted to employees - with self.assertRaises(AccessError): - self.mail_group.read(cr, user_noone_id, [self.group_pigs_id]) - # Do: Raoul read Pigs -> ok, belong to employees - self.mail_group.read(cr, user_employee_id, [self.group_pigs_id]) + # Read Pigs -> ko, restricted to employees + # TODO: Change the except_orm to Warning ( Because here it's call check_access_rule + # which still generate exception in except_orm.So we need to change all + # except_orm to warning in mail module.) + with self.assertRaises(except_orm): + self.group_pigs.sudo(self.user_public).read() - # Do: Bert creates a group -> ko, no access rights - with self.assertRaises(AccessError): - self.mail_group.create(cr, user_noone_id, {'name': 'Test'}) - # Do: Raoul creates a restricted group -> ok - new_group_id = self.mail_group.create(cr, user_employee_id, {'name': 'Test'}) - # Do: Bert added in followers, read -> ok, in followers - self.mail_group.message_subscribe_users(cr, uid, [new_group_id], [user_noone_id]) - self.mail_group.read(cr, user_noone_id, [new_group_id]) + # Read a private group when being a follower: ok + self.group_private.message_subscribe_users(user_ids=[self.user_public.id]) + self.group_private.sudo(self.user_public).read() - # Do: Raoul reads Priv -> ko, private + # Create group: ko, no access rights with self.assertRaises(AccessError): - self.mail_group.read(cr, user_employee_id, [self.group_priv_id]) - # Do: Raoul added in follower, read -> ok, in followers - self.mail_group.message_subscribe_users(cr, uid, [self.group_priv_id], [user_employee_id]) - self.mail_group.read(cr, user_employee_id, [self.group_priv_id]) + self.env['mail.group'].sudo(self.user_public).create({'name': 'Test'}) - # Do: Raoul write on Jobs -> ok - self.mail_group.write(cr, user_employee_id, [self.group_priv_id], {'name': 'modified'}) - # Do: Bert cannot write on Private -> ko (read but no write) + # Update group: ko, no access rights with self.assertRaises(AccessError): - self.mail_group.write(cr, user_noone_id, [self.group_priv_id], {'name': 're-modified'}) - # Test: Bert cannot unlink the group + self.group_public.sudo(self.user_public).write({'name': 'Broutouschnouk'}) + + # Unlink group: ko, no access rights with self.assertRaises(AccessError): - self.mail_group.unlink(cr, user_noone_id, [self.group_priv_id]) - # Do: Raoul unlinks the group, there are no followers and messages left - self.mail_group.unlink(cr, user_employee_id, [self.group_priv_id]) - fol_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', self.group_priv_id)]) - self.assertFalse(fol_ids, 'unlinked document should not have any followers left') - msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_priv_id)]) - self.assertFalse(msg_ids, 'unlinked document should not have any followers left') + self.group_public.sudo(self.user_public).unlink() + + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') + def test_access_rights_groups(self): + # Employee read employee-based group: ok + # TODO Change the except_orm to Warning + self.group_pigs.sudo(self.user_employee).read() + + # Employee can create a group + self.env['mail.group'].sudo(self.user_employee).create({'name': 'Test'}) + + # Employee update employee-based group: ok + self.group_pigs.sudo(self.user_employee).write({'name': 'modified'}) + + # Employee unlink employee-based group: ok + self.group_pigs.sudo(self.user_employee).unlink() + + # Employee cannot read a private group + with self.assertRaises(except_orm): + self.group_private.sudo(self.user_employee).read() + + # Employee cannot write on private + with self.assertRaises(AccessError): + self.group_private.sudo(self.user_employee).write({'name': 're-modified'}) + + def test_access_rights_followers_ko(self): + with self.assertRaises(AccessError): + self.group_private.sudo(self.user_portal).name + + def test_access_rights_followers_portal(self): + # Do: Chell is added into Pigs followers and browse it -> ok for messages, ko for partners (no read permission) + self.group_private.message_subscribe_users(user_ids=[self.user_portal.id]) + chell_pigs = self.group_private.sudo(self.user_portal) + trigger_read = chell_pigs.name + for message in chell_pigs.message_ids: + trigger_read = message.subject + for partner in chell_pigs.message_follower_ids: + if partner.id == self.user_portal.partner_id.id: + # Chell can read her own partner record + continue + # TODO Change the except_orm to Warning + with self.assertRaises(except_orm): + trigger_read = partner.name 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. -# -# 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 . -# -############################################################################## 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 '], link_mail=False)[0] - self.assertEqual(partner_info['full_name'], 'Maybe Raoul ', - '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 '], 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 '], link_mail=False)[0] - self.assertEqual(partner_info['partner_id'], p_b_id, - 'mail_thread: message_partner_info_from_emails wrong partner found') - - class TestMailMessage(TestMail): - def test_00_mail_message_values(self): - """ Tests designed for testing email values based on mail.message, aliases, ... """ - cr, uid, user_raoul_id = self.cr, self.uid, self.user_raoul_id + def setUp(self): + super(TestMailMessage, self).setUp() + self.attachment = self.env['ir.attachment'].create({ + 'datas': 'My attachment'.encode('base64'), + 'name': 'doc.txt', + 'datas_fname': 'doc.txt'}) + self.message = self.env['mail.message'].create({ + 'body': 'My Body', + 'model': 'mail.group', + 'res_id': self.group_private.id, + 'attachment_ids': [(4, self.attachment.id)], + }) - # Data: update + generic variables - reply_to1 = '_reply_to1@example.com' - reply_to2 = '_reply_to2@example.com' - email_from1 = 'from@example.com' - alias_domain = 'schlouby.fr' - raoul_from = 'Raoul Grosbedon ' - raoul_from_alias = 'Raoul Grosbedon ' - raoul_reply_alias = 'YourCompany Pigs ' + def test_mail_message_values_basic(self): + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() - # -------------------------------------------------- - # Case1: without alias_domain - # -------------------------------------------------- - param_ids = self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.domain')]) - self.registry('ir.config_parameter').unlink(cr, uid, param_ids) + msg = self.env['mail.message'].sudo(self.user_employee).create({ + 'reply_to': 'test.reply@example.com', + 'email_from': 'test.from@example.com', + }) + self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, 'test.reply@example.com') + self.assertEqual(msg.email_from, 'test.from@example.com') - # Do: free message; specified values > default values - msg_id = self.mail_message.create(cr, user_raoul_id, {'no_auto_thread': True, 'reply_to': reply_to1, 'email_from': email_from1}) - msg = self.mail_message.browse(cr, user_raoul_id, msg_id) - # Test: message content - self.assertIn('reply_to', msg.message_id, - 'mail_message: message_id should be specific to a mail_message with a given reply_to') - self.assertEqual(msg.reply_to, reply_to1, - 'mail_message: incorrect reply_to: should come from values') - self.assertEqual(msg.email_from, email_from1, - 'mail_message: incorrect email_from: should come from values') + def test_mail_message_values_default(self): + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() - # Do: create a mail_mail with the previous mail_message + specified reply_to - mail_id = self.mail_mail.create(cr, user_raoul_id, {'mail_message_id': msg_id, 'state': 'cancel', 'reply_to': reply_to2}) - mail = self.mail_mail.browse(cr, user_raoul_id, mail_id) - # Test: mail_mail content - self.assertEqual(mail.reply_to, reply_to2, - 'mail_mail: incorrect reply_to: should come from values') - self.assertEqual(mail.email_from, email_from1, - 'mail_mail: incorrect email_from: should come from mail.message') + msg = self.env['mail.message'].sudo(self.user_employee).create({}) + self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) + self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) - # Do: mail_message attached to a document - msg_id = self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_pigs_id}) - msg = self.mail_message.browse(cr, user_raoul_id, msg_id) - # Test: message content - self.assertIn('mail.group', msg.message_id, - 'mail_message: message_id should contain model') - self.assertIn('%s' % self.group_pigs_id, msg.message_id, - 'mail_message: message_id should contain res_id') - self.assertEqual(msg.reply_to, raoul_from, - 'mail_message: incorrect reply_to: should be Raoul') - self.assertEqual(msg.email_from, raoul_from, - 'mail_message: incorrect email_from: should be Raoul') + def test_mail_message_values_alias(self): + alias_domain = 'example.com' + self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain) + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink() - # -------------------------------------------------- - # Case2: with alias_domain, without catchall alias - # -------------------------------------------------- - self.registry('ir.config_parameter').set_param(cr, uid, 'mail.catchall.domain', alias_domain) - self.registry('ir.config_parameter').unlink(cr, uid, self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.alias')])) + msg = self.env['mail.message'].sudo(self.user_employee).create({}) + self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain)) + self.assertEqual(msg.email_from, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain)) - # Update message - msg_id = self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_pigs_id}) - msg = self.mail_message.browse(cr, user_raoul_id, msg_id) - # Test: generated reply_to - self.assertEqual(msg.reply_to, raoul_reply_alias, - 'mail_mail: incorrect reply_to: should be Pigs alias') + def test_mail_message_values_alias_catchall(self): + alias_domain = 'example.com' + alias_catchall = 'pokemon' + self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain) + self.env['ir.config_parameter'].set_param('mail.catchall.alias', alias_catchall) - # Update message: test alias on email_from - msg_id = self.mail_message.create(cr, user_raoul_id, {}) - msg = self.mail_message.browse(cr, user_raoul_id, msg_id) - # Test: generated reply_to - self.assertEqual(msg.reply_to, raoul_from_alias, - 'mail_mail: incorrect reply_to: should be message email_from using Raoul alias') + msg = self.env['mail.message'].sudo(self.user_employee).create({}) + self.assertIn('-private', msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, '%s <%s@%s>' % (self._company_name, alias_catchall, alias_domain)) + self.assertEqual(msg.email_from, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain)) - # -------------------------------------------------- - # Case2: with alias_domain and catchall alias - # -------------------------------------------------- - self.registry('ir.config_parameter').set_param(self.cr, self.uid, 'mail.catchall.alias', 'gateway') + def test_mail_message_values_document_no_alias(self): + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() - # Update message - msg_id = self.mail_message.create(cr, user_raoul_id, {}) - msg = self.mail_message.browse(cr, user_raoul_id, msg_id) - # Test: generated reply_to - self.assertEqual(msg.reply_to, 'YourCompany ', - 'mail_mail: reply_to should equal the catchall email alias') + msg = self.env['mail.message'].sudo(self.user_employee).create({ + 'model': 'mail.group', + 'res_id': self.group_pigs.id + }) + self.assertIn('-openerp-%d-mail.group' % self.group_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) + self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) - # Do: create a mail_mail - mail_id = self.mail_mail.create(cr, uid, {'state': 'cancel', 'reply_to': 'someone@example.com'}) - mail = self.mail_mail.browse(cr, uid, mail_id) - # Test: mail_mail content - self.assertEqual(mail.reply_to, 'someone@example.com', - 'mail_mail: reply_to should equal the rpely_to given to create') + def test_mail_message_values_document_alias(self): + alias_domain = 'example.com' + self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain) + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink() - @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') - def test_10_mail_message_search_access_rights(self): - """ Testing mail_message.search() using specific _search implementation """ - cr, uid, group_pigs_id = self.cr, self.uid, self.group_pigs_id - # Data: comment subtype for mail.message creation - ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'mail', 'mt_comment') - subtype_id = ref and ref[1] or False + msg = self.env['mail.message'].sudo(self.user_employee).create({ + 'model': 'mail.group', + 'res_id': self.group_pigs.id + }) + self.assertIn('-openerp-%d-mail.group' % self.group_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, '%s %s <%s@%s>' % (self._company_name, self.group_pigs.name, self.group_pigs.alias_name, alias_domain)) + self.assertEqual(msg.email_from, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain)) - # Data: Birds group, private - group_birds_id = self.mail_group.create(self.cr, self.uid, {'name': 'Birds', 'public': 'private'}) - # Data: Raoul is member of Pigs - self.mail_group.message_subscribe(cr, uid, [group_pigs_id], [self.partner_raoul_id]) + def test_mail_message_values_document_alias_catchall(self): + alias_domain = 'example.com' + alias_catchall = 'pokemon' + self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain) + self.env['ir.config_parameter'].set_param('mail.catchall.alias', alias_catchall) + + msg = self.env['mail.message'].sudo(self.user_employee).create({ + 'model': 'mail.group', + 'res_id': self.group_pigs.id + }) + self.assertIn('-openerp-%d-mail.group' % self.group_pigs.id, msg.message_id, 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, '%s %s <%s@%s>' % (self._company_name, self.group_pigs.name, self.group_pigs.alias_name, alias_domain)) + self.assertEqual(msg.email_from, '%s <%s@%s>' % (self.user_employee.name, self.user_employee.alias_name, alias_domain)) + + def test_mail_message_values_no_auto_thread(self): + msg = self.env['mail.message'].sudo(self.user_employee).create({ + 'model': 'mail.group', + 'res_id': self.group_pigs.id, + 'no_auto_thread': True, + }) + self.assertIn('reply_to', msg.message_id) + self.assertNotIn('mail.group', msg.message_id) + self.assertNotIn('-%d-' % self.group_pigs.id, msg.message_id) + + @mute_logger('openerp.addons.mail.mail_mail') + def test_mail_message_access_search(self): # Data: various author_ids, partner_ids, documents - msg_id1 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A', 'subtype_id': subtype_id}) - msg_id2 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A+B', 'partner_ids': [(6, 0, [self.partner_bert_id])], 'subtype_id': subtype_id}) - msg_id3 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A Pigs', 'model': 'mail.group', 'res_id': group_pigs_id, 'subtype_id': subtype_id}) - msg_id4 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A+B Pigs', 'model': 'mail.group', 'res_id': group_pigs_id, 'partner_ids': [(6, 0, [self.partner_bert_id])], 'subtype_id': subtype_id}) - msg_id5 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A+R Pigs', 'model': 'mail.group', 'res_id': group_pigs_id, 'partner_ids': [(6, 0, [self.partner_raoul_id])], 'subtype_id': subtype_id}) - msg_id6 = self.mail_message.create(cr, uid, {'subject': '_Test', 'body': 'A Birds', 'model': 'mail.group', 'res_id': group_birds_id, 'subtype_id': subtype_id}) - msg_id7 = self.mail_message.create(cr, self.user_raoul_id, {'subject': '_Test', 'body': 'B', 'subtype_id': subtype_id}) - msg_id8 = self.mail_message.create(cr, self.user_raoul_id, {'subject': '_Test', 'body': 'B+R', 'partner_ids': [(6, 0, [self.partner_raoul_id])], 'subtype_id': subtype_id}) + msg1 = self.env['mail.message'].create({ + 'subject': '_Test', 'body': 'A', 'subtype_id': self.ref('mail.mt_comment')}) + msg2 = self.env['mail.message'].create({ + 'subject': '_Test', 'body': 'A+B', 'subtype_id': self.ref('mail.mt_comment'), + 'partner_ids': [(6, 0, [self.user_public.partner_id.id])]}) + msg3 = self.env['mail.message'].create({ + 'subject': '_Test', 'body': 'A Pigs', 'subtype_id': False, + 'model': 'mail.group', 'res_id': self.group_pigs.id}) + msg4 = self.env['mail.message'].create({ + 'subject': '_Test', 'body': 'A+P Pigs', 'subtype_id': self.ref('mail.mt_comment'), + 'model': 'mail.group', 'res_id': self.group_pigs.id, + 'partner_ids': [(6, 0, [self.user_public.partner_id.id])]}) + msg5 = self.env['mail.message'].create({ + 'subject': '_Test', 'body': 'A+E Pigs', 'subtype_id': self.ref('mail.mt_comment'), + 'model': 'mail.group', 'res_id': self.group_pigs.id, + 'partner_ids': [(6, 0, [self.user_employee.partner_id.id])]}) + msg6 = self.env['mail.message'].create({ + 'subject': '_Test', 'body': 'A Birds', 'subtype_id': self.ref('mail.mt_comment'), + 'model': 'mail.group', 'res_id': self.group_private.id}) + msg7 = self.env['mail.message'].sudo(self.user_employee).create({ + 'subject': '_Test', 'body': 'B', 'subtype_id': self.ref('mail.mt_comment')}) + msg8 = self.env['mail.message'].sudo(self.user_employee).create({ + 'subject': '_Test', 'body': 'B+E', 'subtype_id': self.ref('mail.mt_comment'), + 'partner_ids': [(6, 0, [self.user_employee.partner_id.id])]}) + + # Test: Public: 2 messages (recipient) + messages = self.env['mail.message'].sudo(self.user_public).search([('subject', 'like', '_Test')]) + self.assertEqual(messages, msg2 | msg4) + + # Test: Employee: 3 messages on Pigs Raoul can read (employee can read group with default values) + messages = self.env['mail.message'].sudo(self.user_employee).search([('subject', 'like', '_Test'), ('body', 'ilike', 'A')]) + self.assertEqual(messages, msg3 | msg4 | msg5) - # Test: Bert: 2 messages that have Bert in partner_ids - msg_ids = self.mail_message.search(cr, self.user_bert_id, [('subject', 'like', '_Test')]) - self.assertEqual(set([msg_id2, msg_id4]), set(msg_ids), 'mail_message search failed') - # Test: Raoul: 3 messages on Pigs Raoul can read (employee can read group with default values), 0 on Birds (private group) - msg_ids = self.mail_message.search(cr, self.user_raoul_id, [('subject', 'like', '_Test'), ('body', 'like', 'A')]) - self.assertEqual(set([msg_id3, msg_id4, msg_id5]), set(msg_ids), 'mail_message search failed') # Test: Raoul: 3 messages on Pigs Raoul can read (employee can read group with default values), 0 on Birds (private group) + 2 messages as author - msg_ids = self.mail_message.search(cr, self.user_raoul_id, [('subject', 'like', '_Test')]) - self.assertEqual(set([msg_id3, msg_id4, msg_id5, msg_id7, msg_id8]), set(msg_ids), 'mail_message search failed') + messages = self.env['mail.message'].sudo(self.user_employee).search([('subject', 'like', '_Test')]) + self.assertEqual(messages, msg3 | msg4 | msg5 | msg7 | msg8) + # Test: Admin: all messages - msg_ids = self.mail_message.search(cr, uid, [('subject', 'like', '_Test')]) - self.assertEqual(set([msg_id1, msg_id2, msg_id3, msg_id4, msg_id5, msg_id6, msg_id7, msg_id8]), set(msg_ids), 'mail_message search failed') + messages = self.env['mail.message'].search([('subject', 'like', '_Test')]) + self.assertEqual(messages, msg1 | msg2 | msg3 | msg4 | msg5 | msg6 | msg7 | msg8) + + # Test: Portal: 0 (no access to groups, not recipient) + messages = self.env['mail.message'].sudo(self.user_portal).search([('subject', 'like', '_Test')]) + self.assertFalse(messages) + + # Test: Portal: 2 messages (public group with a subtype) + self.group_pigs.write({'public': 'public'}) + messages = self.env['mail.message'].sudo(self.user_portal).search([('subject', 'like', '_Test')]) + self.assertEqual(messages, msg4 | msg5) @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') - def test_15_mail_message_check_access_rule(self): - """ Testing mail_message.check_access_rule() """ - cr, uid = self.cr, self.uid - partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id - user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id + def test_mail_message_access_read_crash(self): + # TODO: Change the except_orm to Warning ( Because here it's call check_access_rule + # which still generate exception in except_orm.So we need to change all + # except_orm to warning in mail module.) + with self.assertRaises(except_orm): + self.message.sudo(self.user_employee).read() - # Prepare groups: Pigs (employee), Jobs (public) - pigs_msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') - priv_msg_id = self.mail_group.message_post(cr, uid, self.group_priv_id, body='Message') + def test_mail_message_access_read_crash_portal(self): + with self.assertRaises(except_orm): + self.message.sudo(self.user_portal).read(['body', 'type', 'subtype_id']) - # prepare an attachment - attachment_id = self.ir_attachment.create(cr, uid, {'datas': 'My attachment'.encode('base64'), 'name': 'doc.txt', 'datas_fname': 'doc.txt'}) + def test_mail_message_access_read_ok_portal(self): + self.message.write({'subtype_id': self.ref('mail.mt_comment'), 'res_id': self.group_public.id}) + self.message.sudo(self.user_portal).read(['body', 'type', 'subtype_id']) - # ---------------------------------------- - # CASE1: read - # ---------------------------------------- - - # Do: create a new mail.message - message_id = self.mail_message.create(cr, uid, {'body': 'My Body', 'attachment_ids': [(4, attachment_id)]}) - - # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc - with self.assertRaises(AccessError): - self.mail_message.read(cr, user_bert_id, message_id) - # Do: message is pushed to Bert - notif_id = self.mail_notification.create(cr, uid, {'message_id': message_id, 'partner_id': partner_bert_id}) - # Test: Bert reads the message, ok because notification pushed - self.mail_message.read(cr, user_bert_id, message_id) + def test_mail_message_access_read_notification(self): + self.env['mail.notification'].create({'message_id': self.message.id, 'partner_id': self.user_employee.partner_id.id}) + self.message.sudo(self.user_employee).read() # Test: Bert downloads attachment, ok because he can read message - self.mail_message.download_attachment(cr, user_bert_id, message_id, attachment_id) - # Do: remove notification - self.mail_notification.unlink(cr, uid, notif_id) - # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc - with self.assertRaises(AccessError): - self.mail_message.read(cr, self.user_bert_id, message_id) - # Test: Bert downloads attachment, crash because he can't read message - with self.assertRaises(AccessError): - self.mail_message.download_attachment(cr, user_bert_id, message_id, attachment_id) - # Do: Bert is now the author - self.mail_message.write(cr, uid, [message_id], {'author_id': partner_bert_id}) - # Test: Bert reads the message, ok because Bert is the author - self.mail_message.read(cr, user_bert_id, message_id) - # Do: Bert is not the author anymore - self.mail_message.write(cr, uid, [message_id], {'author_id': partner_raoul_id}) - # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc - with self.assertRaises(AccessError): - self.mail_message.read(cr, user_bert_id, message_id) - # Do: message is attached to a document Bert can read, Jobs - self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_jobs_id}) + self.env['mail.message'].sudo(self.user_employee).download_attachment(self.message.id, self.attachment.id) + + def test_mail_message_access_read_author(self): + self.message.write({'author_id': self.user_employee.partner_id.id}) + self.message.sudo(self.user_employee).read() + + def test_mail_message_access_read_doc(self): + self.message.write({'model': 'mail.group', 'res_id': self.group_public.id}) # Test: Bert reads the message, ok because linked to a doc he is allowed to read - self.mail_message.read(cr, user_bert_id, message_id) - # Do: message is attached to a document Bert cannot read, Pigs - self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_pigs_id}) - # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc - with self.assertRaises(AccessError): - self.mail_message.read(cr, user_bert_id, message_id) - - # ---------------------------------------- - # CASE2: create - # ---------------------------------------- + self.message.sudo(self.user_employee).read() + @mute_logger('openerp.addons.base.ir.ir_model') + def test_mail_message_access_create_crash_public(self): # Do: Bert creates a message on Pigs -> ko, no creation rights with self.assertRaises(AccessError): - self.mail_message.create(cr, user_bert_id, {'model': 'mail.group', 'res_id': self.group_pigs_id, 'body': 'Test'}) + self.env['mail.message'].sudo(self.user_public).create({'model': 'mail.group', 'res_id': self.group_pigs.id, 'body': 'Test'}) + # Do: Bert create a message on Jobs -> ko, no creation rights with self.assertRaises(AccessError): - self.mail_message.create(cr, user_bert_id, {'model': 'mail.group', 'res_id': self.group_jobs_id, 'body': 'Test'}) + self.env['mail.message'].sudo(self.user_public).create({'model': 'mail.group', 'res_id': self.group_public.id, 'body': 'Test'}) + + def test_mail_message_access_create_crash(self): # Do: Bert create a private message -> ko, no creation rights - with self.assertRaises(AccessError): - self.mail_message.create(cr, user_bert_id, {'body': 'Test'}) + with self.assertRaises(except_orm): + self.env['mail.message'].sudo(self.user_employee).create({'model': 'mail.group', 'res_id': self.group_private.id, 'body': 'Test'}) + @mute_logger('openerp.models') + def test_mail_message_access_create_doc(self): + # TODO Change the except_orm to Warning + Message = self.env['mail.message'].sudo(self.user_employee) # Do: Raoul creates a message on Jobs -> ok, write access to the related document - self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_jobs_id, 'body': 'Test'}) + Message.create({'model': 'mail.group', 'res_id': self.group_public.id, 'body': 'Test'}) # Do: Raoul creates a message on Priv -> ko, no write access to the related document - with self.assertRaises(AccessError): - self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test'}) - # Do: Raoul creates a private message -> ok - self.mail_message.create(cr, user_raoul_id, {'body': 'Test'}) - # Do: Raoul creates a reply to a message on Priv -> ko - with self.assertRaises(AccessError): - self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id}) - # Do: Raoul creates a reply to a message on Priv-> ok if has received parent - self.mail_notification.create(cr, uid, {'message_id': priv_msg_id, 'partner_id': self.partner_raoul_id}) - self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id}) + with self.assertRaises(except_orm): + Message.create({'model': 'mail.group', 'res_id': self.group_private.id, 'body': 'Test'}) - def test_20_message_set_star(self): - """ Tests for starring messages and its related access rights """ - cr, uid = self.cr, self.uid - # Data: post a message on Pigs + def test_mail_message_access_create_private(self): + self.env['mail.message'].sudo(self.user_employee).create({'body': 'Test'}) + + def test_mail_message_access_create_reply(self): + self.env['mail.notification'].create({'message_id': self.message.id, 'partner_id': self.user_employee.partner_id.id}) + self.env['mail.message'].sudo(self.user_employee).create({'model': 'mail.group', 'res_id': self.group_private.id, 'body': 'Test', 'parent_id': self.message.id}) + + def test_message_set_star(self): msg_id = self.group_pigs.message_post(body='My Body', subject='1') - msg = self.mail_message.browse(cr, uid, msg_id) - msg_raoul = self.mail_message.browse(cr, self.user_raoul_id, msg_id) + msg = self.env['mail.message'].browse(msg_id) + msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg_id) - # Do: Admin stars msg - self.mail_message.set_message_starred(cr, uid, [msg.id], True) - msg.refresh() - # Test: notification exists - notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', self.partner_admin_id), ('message_id', '=', msg.id)]) - self.assertEqual(len(notif_ids), 1, 'mail_message set_message_starred: more than one notification created') - # Test: notification starred - notif = self.mail_notification.browse(cr, uid, notif_ids[0]) - self.assertTrue(notif.starred, 'mail_notification starred failed') - self.assertTrue(msg.starred, 'mail_message starred failed') + # Admin set as starred + msg.set_message_starred(True) + notification = self.env['mail.notification'].search([('partner_id', '=', self.env.user.partner_id.id), ('message_id', '=', msg.id)]) + self.assertEqual(len(notification), 1) + self.assertTrue(notification.starred) + self.assertTrue(msg.starred) - # Do: Raoul stars msg - self.mail_message.set_message_starred(cr, self.user_raoul_id, [msg.id], True) - msg_raoul.refresh() - # Test: notification exists - notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', self.partner_raoul_id), ('message_id', '=', msg.id)]) - self.assertEqual(len(notif_ids), 1, 'mail_message set_message_starred: more than one notification created') - # Test: notification starred - notif = self.mail_notification.browse(cr, uid, notif_ids[0]) - self.assertTrue(notif.starred, 'mail_notification starred failed') - self.assertTrue(msg_raoul.starred, 'mail_message starred failed') + # Employee set as starred + msg_emp.set_message_starred(True) + notification = self.env['mail.notification'].search([('partner_id', '=', self.user_employee.partner_id.id), ('message_id', '=', msg.id)]) + self.assertEqual(len(notification), 1) + self.assertTrue(notification.starred) + self.assertTrue(msg_emp.starred) # Do: Admin unstars msg - self.mail_message.set_message_starred(cr, uid, [msg.id], False) - msg.refresh() - msg_raoul.refresh() - # Test: msg unstarred for Admin, starred for Raoul - self.assertFalse(msg.starred, 'mail_message starred failed') - self.assertTrue(msg_raoul.starred, 'mail_message starred failed') + msg.set_message_starred(False) + self.assertFalse(msg.starred) + self.assertTrue(msg_emp.starred) - def test_30_message_set_read(self): - """ Tests for reading messages and its related access rights """ - cr, uid = self.cr, self.uid - # Data: post a message on Pigs + def test_message_set_read(self): msg_id = self.group_pigs.message_post(body='My Body', subject='1') - msg = self.mail_message.browse(cr, uid, msg_id) - msg_raoul = self.mail_message.browse(cr, self.user_raoul_id, msg_id) + msg = self.env['mail.message'].browse(msg_id) + msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg_id) - # Do: Admin reads msg - self.mail_message.set_message_read(cr, uid, [msg.id], True) - msg.refresh() - # Test: notification exists - notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', self.partner_admin_id), ('message_id', '=', msg.id)]) - self.assertEqual(len(notif_ids), 1, 'mail_message set_message_read: more than one notification created') - # Test: notification read - notif = self.mail_notification.browse(cr, uid, notif_ids[0]) - self.assertTrue(notif['is_read'], 'mail_notification read failed') - self.assertFalse(msg.to_read, 'mail_message read failed') + # Admin set as read + msg.set_message_read(True) + notification = self.env['mail.notification'].search([('partner_id', '=', self.env.user.partner_id.id), ('message_id', '=', msg.id)]) + self.assertEqual(len(notification), 1) + self.assertTrue(notification.is_read) + self.assertFalse(msg.to_read) - # Do: Raoul reads msg - self.mail_message.set_message_read(cr, self.user_raoul_id, [msg.id], True) - msg_raoul.refresh() - # Test: notification exists - notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', self.partner_raoul_id), ('message_id', '=', msg.id)]) - self.assertEqual(len(notif_ids), 1, 'mail_message set_message_read: more than one notification created') - # Test: notification read - notif = self.mail_notification.browse(cr, uid, notif_ids[0]) - self.assertTrue(notif['is_read'], 'mail_notification starred failed') - self.assertFalse(msg_raoul.to_read, 'mail_message starred failed') + # Employee set as read + msg_emp.set_message_read(True) + notification = self.env['mail.notification'].search([('partner_id', '=', self.user_employee.partner_id.id), ('message_id', '=', msg.id)]) + self.assertEqual(len(notification), 1, 'mail_message set_message_read: more than one notification created') + self.assertTrue(notification.is_read) + self.assertFalse(msg_emp.to_read) # Do: Admin unreads msg - self.mail_message.set_message_read(cr, uid, [msg.id], False) - msg.refresh() - msg_raoul.refresh() - # Test: msg unread for Admin, read for Raoul - self.assertTrue(msg.to_read, 'mail_message read failed') - self.assertFalse(msg_raoul.to_read, 'mail_message read failed') + msg.set_message_read(False) + self.assertTrue(msg.to_read) + self.assertFalse(msg_emp.to_read) - def test_40_message_vote(self): - """ Test designed for the vote/unvote feature. """ - cr, uid = self.cr, self.uid - # Data: post a message on Pigs + def test_message_vote(self): msg_id = self.group_pigs.message_post(body='My Body', subject='1') - msg = self.mail_message.browse(cr, uid, msg_id) - msg_raoul = self.mail_message.browse(cr, self.user_raoul_id, msg_id) + msg = self.env['mail.message'].browse(msg_id) + msg_emp = self.env['mail.message'].sudo(self.user_employee).browse(msg_id) # Do: Admin vote for msg - self.mail_message.vote_toggle(cr, uid, [msg.id]) - msg.refresh() - # Test: msg has Admin as voter - self.assertEqual(set(msg.vote_user_ids), set([self.user_admin]), 'mail_message vote: after voting, Admin should be in the voter') + msg.vote_toggle() + self.assertEqual(msg.vote_user_ids, self.user_admin) + # Do: Bert vote for msg - self.mail_message.vote_toggle(cr, self.user_raoul_id, [msg.id]) - msg_raoul.refresh() + msg_emp.vote_toggle() # Test: msg has Admin and Bert as voters - self.assertEqual(set(msg_raoul.vote_user_ids), set([self.user_admin, self.user_raoul]), 'mail_message vote: after voting, Admin and Bert should be in the voters') + self.assertEqual(msg_emp.vote_user_ids, self.user_admin | self.user_employee) + # Do: Admin unvote for msg - self.mail_message.vote_toggle(cr, uid, [msg.id]) - msg.refresh() - msg_raoul.refresh() + msg.vote_toggle() # Test: msg has Bert as voter - self.assertEqual(set(msg.vote_user_ids), set([self.user_raoul]), 'mail_message vote: after unvoting, Bert should be in the voter') - self.assertEqual(set(msg_raoul.vote_user_ids), set([self.user_raoul]), 'mail_message vote: after unvoting, Bert should be in the voter') - - @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') - def test_50_mail_flow_access_rights(self): - """ Test a Chatter-looks alike flow to test access rights """ - cr, uid = self.cr, self.uid - mail_compose = self.registry('mail.compose.message') - partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id - user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id - - # Prepare groups: Pigs (employee), Jobs (public) - pigs_msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message', partner_ids=[self.partner_admin_id]) - jobs_msg_id = self.mail_group.message_post(cr, uid, self.group_jobs_id, body='Message', partner_ids=[self.partner_admin_id]) - - # ---------------------------------------- - # CASE1: Bert, without groups - # ---------------------------------------- - - # Do: Bert reads Jobs basic fields, ok because public = read access on the group - self.mail_group.read(cr, user_bert_id, [self.group_jobs_id], ['name', 'description']) - # Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages - jobs_message_ids = self.mail_group.read(cr, user_bert_id, [self.group_jobs_id], ['message_ids'])[0]['message_ids'] - self.mail_message.read(cr, user_bert_id, jobs_message_ids) - # Do: Bert browses Jobs, ok (no direct browse of partners), ok for messages, ko for followers (accessible to employees or partner manager) - bert_jobs = self.mail_group.browse(cr, user_bert_id, self.group_jobs_id) - trigger_read = bert_jobs.name - for message in bert_jobs.message_ids: - trigger_read = message.subject - for partner in bert_jobs.message_follower_ids: - with self.assertRaises(AccessError): - trigger_read = partner.name - # Do: Bert comments Jobs, ko because no creation right - with self.assertRaises(AccessError): - self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') - - # Do: Bert writes on its own profile, ko because no message create access - with self.assertRaises(AccessError): - self.res_users.message_post(cr, user_bert_id, user_bert_id, body='I love Bert') - self.res_partner.message_post(cr, user_bert_id, partner_bert_id, body='I love Bert') - - # ---------------------------------------- - # CASE2: Raoul, employee - # ---------------------------------------- - - # Do: Raoul browses Jobs -> ok, ok for message_ids, of for message_follower_ids - raoul_jobs = self.mail_group.browse(cr, user_raoul_id, self.group_jobs_id) - trigger_read = raoul_jobs.name - for message in raoul_jobs.message_ids: - trigger_read = message.subject - for partner in raoul_jobs.message_follower_ids: - trigger_read = partner.name - - # Do: Raoul comments Jobs, ok - self.mail_group.message_post(cr, user_raoul_id, self.group_jobs_id, body='I love Pigs') - # Do: Raoul create a mail.compose.message record on Jobs, because he uses the wizard - compose_id = mail_compose.create(cr, user_raoul_id, - {'subject': 'Subject', 'body': 'Body text', 'partner_ids': []}, - {'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_jobs_id}) - mail_compose.send_mail(cr, user_raoul_id, [compose_id]) - # Do: Raoul replies to a Jobs message using the composer - compose_id = mail_compose.create(cr, user_raoul_id, - {'subject': 'Subject', 'body': 'Body text'}, - {'default_composition_mode': 'comment', 'default_parent_id': pigs_msg_id}) - mail_compose.send_mail(cr, user_raoul_id, [compose_id]) + self.assertEqual(msg.vote_user_ids, self.user_employee) + self.assertEqual(msg_emp.vote_user_ids, self.user_employee) 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'], '

%s

' % 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, '

%s

' % 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 ->

False

) + + 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': '

Dummy body

' + }).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, '

Dummy body

', '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. -# -# 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 . -# -############################################################################## from openerp.addons.mail.tests.common import TestMail +from openerp.tools import mute_logger -class test_mail_access_rights(TestMail): +class TestMessageRead(TestMail): - def test_00_message_read(self): - """ Tests for message_read and expandables. """ - cr, uid, user_admin, user_raoul, group_pigs = self.cr, self.uid, self.user_admin, self.user_raoul, self.group_pigs - self.mail_group.message_subscribe_users(cr, uid, [group_pigs.id], [user_raoul.id]) - pigs_domain = [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)] + @mute_logger('openerp.addons.mail.mail_mail') + def setUp(self): + super(TestMessageRead, self).setUp() + self.group_pigs.message_subscribe_users([self.user_employee.id]) + self.msg_id0 = self.group_pigs.message_post(body='0', subtype='mt_comment') + self.msg_id1 = self.group_pigs.message_post(body='1', subtype='mt_comment') + self.msg_id2 = self.group_pigs.message_post(body='2', subtype='mt_comment') + self.msg_id3 = self.group_pigs.message_post(body='1-1', subtype='mt_comment', parent_id=self.msg_id1) + self.msg_id4 = self.group_pigs.message_post(body='2-1', subtype='mt_comment', parent_id=self.msg_id2) + self.msg_id5 = self.group_pigs.message_post(body='1-2', subtype='mt_comment', parent_id=self.msg_id1) + self.msg_id6 = self.group_pigs.message_post(body='2-2', subtype='mt_comment', parent_id=self.msg_id2) + self.msg_id7 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=self.msg_id3) + self.msg_id8 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=self.msg_id4) + self.msg_id9 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=self.msg_id3) + self.msg_id10 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=self.msg_id4) + self.msg_ids = [self.msg_id10, self.msg_id9, self.msg_id8, self.msg_id7, self.msg_id6, self.msg_id5, self.msg_id4, self.msg_id3, self.msg_id2, self.msg_id1, self.msg_id0] + self.ordered_msg_ids = [self.msg_id2, self.msg_id4, self.msg_id6, self.msg_id8, self.msg_id10, self.msg_id1, self.msg_id3, self.msg_id5, self.msg_id7, self.msg_id9, self.msg_id0] - # Data: create a discussion in Pigs (3 threads, with respectively 0, 4 and 4 answers) - msg_id0 = self.group_pigs.message_post(body='0', subtype='mt_comment') - msg_id1 = self.group_pigs.message_post(body='1', subtype='mt_comment') - msg_id2 = self.group_pigs.message_post(body='2', subtype='mt_comment') - msg_id3 = self.group_pigs.message_post(body='1-1', subtype='mt_comment', parent_id=msg_id1) - msg_id4 = self.group_pigs.message_post(body='2-1', subtype='mt_comment', parent_id=msg_id2) - msg_id5 = self.group_pigs.message_post(body='1-2', subtype='mt_comment', parent_id=msg_id1) - msg_id6 = self.group_pigs.message_post(body='2-2', subtype='mt_comment', parent_id=msg_id2) - msg_id7 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=msg_id3) - msg_id8 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=msg_id4) - msg_id9 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=msg_id3) - msg_id10 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=msg_id4) - msg_ids = [msg_id10, msg_id9, msg_id8, msg_id7, msg_id6, msg_id5, msg_id4, msg_id3, msg_id2, msg_id1, msg_id0] - ordered_msg_ids = [msg_id2, msg_id4, msg_id6, msg_id8, msg_id10, msg_id1, msg_id3, msg_id5, msg_id7, msg_id9, msg_id0] + # TODO: with_context({'mail_read_set_read': True}) - # Test: raoul received notifications - raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('is_read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) - self.assertEqual(len(raoul_notification_ids), 11, 'message_post: wrong number of produced notifications') + def test_message_read_ids(self): + """ message_read: test reading specific ids """ + messages = self.env['mail.message'].sudo(self.user_employee).message_read(self.msg_ids[2:4], domain=[('body', 'like', 'dummy')]) + read_msg_ids = [msg.get('id') for msg in messages] + self.assertEqual(read_msg_ids, self.msg_ids[2:4], 'message_read with direct ids should read only the requested ids') - # Test: read some specific ids - read_msg_list = self.mail_message.message_read(cr, user_raoul.id, ids=msg_ids[2:4], domain=[('body', 'like', 'dummy')], context={'mail_read_set_read': True}) - read_msg_ids = [msg.get('id') for msg in read_msg_list] - self.assertEqual(msg_ids[2:4], read_msg_ids, 'message_read with direct ids should read only the requested ids') + def test_message_read_domain(self): + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)], limit=200) + read_msg_ids = [msg.get('id') for msg in messages] + self.assertEqual(read_msg_ids, self.msg_ids, 'message_read flat with domain on Pigs should equal all messages of Pigs') - # Test: read messages of Pigs through a domain, being thread or not threaded - read_msg_list = self.mail_message.message_read(cr, user_raoul.id, domain=pigs_domain, limit=200) - read_msg_ids = [msg.get('id') for msg in read_msg_list] - self.assertEqual(msg_ids, read_msg_ids, 'message_read flat with domain on Pigs should equal all messages of Pigs') - read_msg_list = self.mail_message.message_read(cr, user_raoul.id, domain=pigs_domain, limit=200, thread_level=1) - read_msg_ids = [msg.get('id') for msg in read_msg_list] - self.assertEqual(ordered_msg_ids, read_msg_ids, - 'message_read threaded with domain on Pigs should equal all messages of Pigs, and sort them with newer thread first, last message last in thread') + def test_message_read_domain_thread(self): + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)], limit=200, thread_level=1) + read_msg_ids = [msg.get('id') for msg in messages] + self.assertEqual(read_msg_ids, self.ordered_msg_ids, 'message_read threaded with domain on Pigs should equal all messages of Pigs, and sort them with newer thread first, last message last in thread') - # ---------------------------------------- - # CASE1: message_read with domain, threaded - # We simulate an entire flow, using the expandables to test them - # ---------------------------------------- - - # Do: read last message, threaded - read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=1, thread_level=1) - read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] + def test_message_read_expandable(self): + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)], limit=1, thread_level=1) + read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable'] # TDE TODO: test expandables order - type_list = map(lambda item: item.get('type'), read_msg_list) + type_list = map(lambda item: item.get('type'), messages) # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables - self.assertEqual(len(read_msg_list), 4, 'message_read on last Pigs message should return 2 messages and 2 expandables') - self.assertEqual(set([msg_id2, msg_id10]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent') - self.assertEqual(read_msg_list[1].get('parent_id'), read_msg_list[0].get('id'), 'message_read should set the ancestor to the thread header') + self.assertEqual(len(messages), 4, 'message_read on last Pigs message should return 2 messages and 2 expandables') + self.assertEqual(set([self.msg_id2, self.msg_id10]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent') + self.assertEqual(messages[1].get('parent_id'), messages[0].get('id'), 'message_read should set the ancestor to the thread header') # Data: get expandables new_threads_exp, new_msg_exp = None, None - for msg in read_msg_list: + for msg in messages: if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'): new_threads_exp = msg elif msg.get('type') == 'expandable': @@ -89,101 +63,98 @@ class test_mail_access_rights(TestMail): self.assertIsNotNone(new_msg_exp, 'message_read on last Pigs message should have returned a new messages expandable') domain = new_msg_exp.get('domain', []) # Test: expandable, conditions in domain - self.assertIn(('id', 'child_of', msg_id2), domain, 'new messages expandable domain should contain a child_of condition') - self.assertIn(('id', '>=', msg_id4), domain, 'new messages expandable domain should contain an id greater than condition') - self.assertIn(('id', '<=', msg_id8), domain, 'new messages expandable domain should contain an id less than condition') - self.assertEqual(new_msg_exp.get('parent_id'), msg_id2, 'new messages expandable should have parent_id set to the thread header') + self.assertIn(('id', 'child_of', self.msg_id2), domain, 'new messages expandable domain should contain a child_of condition') + self.assertIn(('id', '>=', self.msg_id4), domain, 'new messages expandable domain should contain an id greater than condition') + self.assertIn(('id', '<=', self.msg_id8), domain, 'new messages expandable domain should contain an id less than condition') + self.assertEqual(new_msg_exp.get('parent_id'), self.msg_id2, 'new messages expandable should have parent_id set to the thread header') # Do: message_read with domain, thread_level=0, parent_id=msg_id2 (should be imposed by JS), 2 messages - read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=2, thread_level=0, parent_id=msg_id2) - read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] - new_msg_exp = [msg for msg in read_msg_list if msg.get('type') == 'expandable'][0] + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=2, thread_level=0, parent_id=self.msg_id2) + read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable'] + new_msg_exp = [msg for msg in messages if msg.get('type') == 'expandable'][0] # Test: structure content, 2 messages and 1 thread expandable - self.assertEqual(len(read_msg_list), 3, 'message_read in Pigs thread should return 2 messages and 1 expandables') - self.assertEqual(set([msg_id6, msg_id8]), set(read_msg_ids), 'message_read in Pigs thread should return 2 more previous messages in thread') + self.assertEqual(len(messages), 3, 'message_read in Pigs thread should return 2 messages and 1 expandables') + self.assertEqual(set([self.msg_id6, self.msg_id8]), set(read_msg_ids), 'message_read in Pigs thread should return 2 more previous messages in thread') # Do: read the last message - read_msg_list = self.mail_message.message_read(cr, uid, domain=new_msg_exp.get('domain'), limit=2, thread_level=0, parent_id=msg_id2) - read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=new_msg_exp.get('domain'), limit=2, thread_level=0, parent_id=self.msg_id2) + read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable'] # Test: structure content, 1 message - self.assertEqual(len(read_msg_list), 1, 'message_read in Pigs thread should return 1 message') - self.assertEqual(set([msg_id4]), set(read_msg_ids), 'message_read in Pigs thread should return the last message in thread') - + self.assertEqual(len(messages), 1, 'message_read in Pigs thread should return 1 message') + self.assertEqual(set([self.msg_id4]), set(read_msg_ids), 'message_read in Pigs thread should return the last message in thread') # Do: fetch a new thread, domain from expandable self.assertIsNotNone(new_threads_exp, 'message_read on last Pigs message should have returned a new threads expandable') domain = new_threads_exp.get('domain', []) # Test: expandable, conditions in domain - for condition in pigs_domain: + for condition in [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)]: self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter') self.assertFalse(new_threads_exp.get('parent_id'), 'new threads expandable should not have an parent_id') # Do: message_read with domain, thread_level=1 (should be imposed by JS) - read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=1, thread_level=1) - read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=1, thread_level=1) + read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable'] # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables - self.assertEqual(len(read_msg_list), 4, 'message_read on Pigs should return 2 messages and 2 expandables') - self.assertEqual(set([msg_id1, msg_id9]), set(read_msg_ids), 'message_read on a Pigs message should also get its parent') - self.assertEqual(read_msg_list[1].get('parent_id'), read_msg_list[0].get('id'), 'message_read should set the ancestor to the thread header') + self.assertEqual(len(messages), 4, 'message_read on Pigs should return 2 messages and 2 expandables') + self.assertEqual(set([self.msg_id1, self.msg_id9]), set(read_msg_ids), 'message_read on a Pigs message should also get its parent') + self.assertEqual(messages[1].get('parent_id'), messages[0].get('id'), 'message_read should set the ancestor to the thread header') # Data: get expandables new_threads_exp, new_msg_exp = None, None - for msg in read_msg_list: + for msg in messages: if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'): new_threads_exp = msg elif msg.get('type') == 'expandable': new_msg_exp = msg - # Do: fetch new messages in second thread, domain from expandable self.assertIsNotNone(new_msg_exp, 'message_read on Pigs message should have returned a new messages expandable') domain = new_msg_exp.get('domain', []) # Test: expandable, conditions in domain - self.assertIn(('id', 'child_of', msg_id1), domain, 'new messages expandable domain should contain a child_of condition') - self.assertIn(('id', '>=', msg_id3), domain, 'new messages expandable domain should contain an id greater than condition') - self.assertIn(('id', '<=', msg_id7), domain, 'new messages expandable domain should contain an id less than condition') - self.assertEqual(new_msg_exp.get('parent_id'), msg_id1, 'new messages expandable should have ancestor_id set to the thread header') + self.assertIn(('id', 'child_of', self.msg_id1), domain, 'new messages expandable domain should contain a child_of condition') + self.assertIn(('id', '>=', self.msg_id3), domain, 'new messages expandable domain should contain an id greater than condition') + self.assertIn(('id', '<=', self.msg_id7), domain, 'new messages expandable domain should contain an id less than condition') + self.assertEqual(new_msg_exp.get('parent_id'), self.msg_id1, 'new messages expandable should have ancestor_id set to the thread header') # Do: message_read with domain, thread_level=0, parent_id=msg_id1 (should be imposed by JS) - read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=200, thread_level=0, parent_id=msg_id1) - read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=200, thread_level=0, parent_id=self.msg_id1) + read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable'] # Test: other message in thread have been fetch - self.assertEqual(set([msg_id3, msg_id5, msg_id7]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent') + self.assertEqual(set([self.msg_id3, self.msg_id5, self.msg_id7]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent') # Test: fetch a new thread, domain from expandable self.assertIsNotNone(new_threads_exp, 'message_read should have returned a new threads expandable') domain = new_threads_exp.get('domain', []) # Test: expandable, conditions in domain - for condition in pigs_domain: + for condition in [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)]: self.assertIn(condition, domain, 'general expandable domain should contain the message_read domain parameter') # Do: message_read with domain, thread_level=1 (should be imposed by JS) - read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=1, thread_level=1) - read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=1, thread_level=1) + read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable'] # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables - self.assertEqual(len(read_msg_list), 1, 'message_read on Pigs should return 1 message because everything else has been fetched') - self.assertEqual([msg_id0], read_msg_ids, 'message_read after 2 More should return only 1 last message') + self.assertEqual(len(messages), 1, 'message_read on Pigs should return 1 message because everything else has been fetched') + self.assertEqual([self.msg_id0], read_msg_ids, 'message_read after 2 More should return only 1 last message') # ---------------------------------------- # CASE2: message_read with domain, flat # ---------------------------------------- # Do: read 2 lasts message, flat - read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=2, thread_level=0) - read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)], limit=2, thread_level=0) + read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable'] # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is not set, 1 expandable - self.assertEqual(len(read_msg_list), 3, 'message_read on last Pigs message should return 2 messages and 1 expandable') - self.assertEqual(set([msg_id9, msg_id10]), set(read_msg_ids), 'message_read flat on Pigs last messages should only return those messages') - self.assertFalse(read_msg_list[0].get('parent_id'), 'message_read flat should set the ancestor as False') - self.assertFalse(read_msg_list[1].get('parent_id'), 'message_read flat should set the ancestor as False') + self.assertEqual(len(messages), 3, 'message_read on last Pigs message should return 2 messages and 1 expandable') + self.assertEqual(set([self.msg_id9, self.msg_id10]), set(read_msg_ids), 'message_read flat on Pigs last messages should only return those messages') + self.assertFalse(messages[0].get('parent_id'), 'message_read flat should set the ancestor as False') + self.assertFalse(messages[1].get('parent_id'), 'message_read flat should set the ancestor as False') # Data: get expandables new_threads_exp, new_msg_exp = None, None - for msg in read_msg_list: + for msg in messages: if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'): new_threads_exp = msg - # Do: fetch new messages, domain from expandable self.assertIsNotNone(new_threads_exp, 'message_read flat on the 2 last Pigs messages should have returns a new threads expandable') domain = new_threads_exp.get('domain', []) # Test: expandable, conditions in domain - for condition in pigs_domain: + for condition in [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs.id)]: self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter') # Do: message_read with domain, thread_level=0 (should be imposed by JS) - read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=20, thread_level=0) - read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable'] + messages = self.env['mail.message'].sudo(self.user_employee).message_read(domain=domain, limit=20, thread_level=0) + read_msg_ids = [msg.get('id') for msg in messages if msg.get('type') != 'expandable'] # Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables - self.assertEqual(len(read_msg_list), 9, 'message_read on Pigs should return 9 messages and 0 expandable') - self.assertEqual([msg_id8, msg_id7, msg_id6, msg_id5, msg_id4, msg_id3, msg_id2, msg_id1, msg_id0], read_msg_ids, + self.assertEqual(len(messages), 9, 'message_read on Pigs should return 9 messages and 0 expandable') + self.assertEqual([self.msg_id8, self.msg_id7, self.msg_id6, self.msg_id5, self.msg_id4, self.msg_id3, self.msg_id2, self.msg_id1, self.msg_id0], read_msg_ids, 'message_read, More on flat, should return all remaning messages') 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. -# -# 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 . -# -############################################################################## -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. -# -# 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 . -# -############################################################################## from openerp.addons.mail.tests.common import TestMail -from openerp.exceptions import AccessError from openerp.tools.misc import mute_logger class test_portal(TestMail): - def setUp(self): - super(test_portal, self).setUp() - cr, uid = self.cr, self.uid + def test_mail_compose_access_rights(self): + port_msg_id = self.group_portal.message_post(body='Message') - # Find Portal group - group_portal = self.registry('ir.model.data').get_object(cr, uid, 'base', 'group_portal') - self.group_portal_id = group_portal.id - - # Create Chell (portal user) - self.user_chell_id = self.res_users.create(cr, uid, {'name': 'Chell Gladys', 'login': 'chell', 'email': 'chell@gladys.portal', 'groups_id': [(6, 0, [self.group_portal_id])]}) - self.user_chell = self.res_users.browse(cr, uid, self.user_chell_id) - self.partner_chell_id = self.user_chell.partner_id.id - - # Create a PigsPortal group - self.group_port_id = self.mail_group.create(cr, uid, - {'name': 'PigsPortal', 'public': 'groups', 'group_public_id': self.group_portal_id}, - {'mail_create_nolog': True}) - - # Set an email address for the user running the tests, used as Sender for outgoing mails - self.res_users.write(cr, uid, uid, {'email': 'test@localhost'}) - - @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') - def test_00_mail_access_rights(self): - """ Test basic mail_message and mail_group access rights for portal users. """ - cr, uid = self.cr, self.uid - mail_compose = self.registry('mail.compose.message') - - # Prepare group: Pigs and PigsPortal - pigs_msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') - port_msg_id = self.mail_group.message_post(cr, uid, self.group_port_id, body='Message') - - # Do: Chell browses Pigs -> ko, employee group - chell_pigs = self.mail_group.browse(cr, self.user_chell_id, self.group_pigs_id) - with self.assertRaises(AccessError): - trigger_read = chell_pigs.name - - # Do: Chell posts a message on Pigs, crash because can not write on group or is not in the followers - with self.assertRaises(AccessError): - self.mail_group.message_post(cr, self.user_chell_id, self.group_pigs_id, body='Message') - - # Do: Chell is added into Pigs followers and browse it -> ok for messages, ko for partners (no read permission) - self.mail_group.message_subscribe_users(cr, uid, [self.group_pigs_id], [self.user_chell_id]) - chell_pigs = self.mail_group.browse(cr, self.user_chell_id, self.group_pigs_id) - trigger_read = chell_pigs.name - for message in chell_pigs.message_ids: - trigger_read = message.subject - for partner in chell_pigs.message_follower_ids: - if partner.id == self.partner_chell_id: - # Chell can read her own partner record - continue - with self.assertRaises(AccessError): - trigger_read = partner.name - - # Do: Chell comments Pigs, ok because he is now in the followers - self.mail_group.message_post(cr, self.user_chell_id, self.group_pigs_id, body='I love Pigs') + # Do: Chell comments Pigs, ok because can write on it (public group) + self.group_portal.sudo(self.user_portal).message_post(body='I love Pigs') # Do: Chell creates a mail.compose.message record on Pigs, because he uses the wizard - compose_id = mail_compose.create(cr, self.user_chell_id, - {'subject': 'Subject', 'body': 'Body text', 'partner_ids': []}, - {'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id}) - mail_compose.send_mail(cr, self.user_chell_id, [compose_id]) + compose = self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'comment', + 'default_model': 'mail.group', + 'default_res_id': self.group_portal.id + }).sudo(self.user_portal).create({ + 'subject': 'Subject', + 'body': 'Body text', + 'partner_ids': []}) + compose.send_mail() + # Do: Chell replies to a Pigs message using the composer - compose_id = mail_compose.create(cr, self.user_chell_id, - {'subject': 'Subject', 'body': 'Body text'}, - {'default_composition_mode': 'comment', 'default_parent_id': pigs_msg_id}) - mail_compose.send_mail(cr, self.user_chell_id, [compose_id]) + compose = self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'comment', + 'default_parent_id': port_msg_id + }).sudo(self.user_portal).create({ + 'subject': 'Subject', + 'body': 'Body text'}) + compose.send_mail() - # Do: Chell browses PigsPortal -> ok because groups security, ko for partners (no read permission) - chell_port = self.mail_group.browse(cr, self.user_chell_id, self.group_port_id) - trigger_read = chell_port.name - for message in chell_port.message_ids: - trigger_read = message.subject - for partner in chell_port.message_follower_ids: - with self.assertRaises(AccessError): - trigger_read = partner.name - - def test_10_mail_invite(self): - cr, uid = self.cr, self.uid - mail_invite = self.registry('mail.wizard.invite') - base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='') + @mute_logger('openerp.addons.mail.mail_mail') + def test_invite_email_portal(self): + group_pigs = self.group_pigs + base_url = self.env['ir.config_parameter'].get_param('web.base.url', default='') # Carine Poilvache, with email, should receive emails for comments and emails - partner_carine_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c'}) + partner_carine = self.env['res.partner'].create({'name': 'Carine Poilvache', 'email': 'c@c'}) # Do: create a mail_wizard_invite, validate it self._init_mock_build_email() - context = {'default_res_model': 'mail.group', 'default_res_id': self.group_pigs_id} - mail_invite_id = mail_invite.create(cr, uid, {'partner_ids': [(4, partner_carine_id)], 'send_mail': True}, context) - mail_invite.add_followers(cr, uid, [mail_invite_id]) - + mail_invite = self.env['mail.wizard.invite'].with_context({ + 'default_res_model': 'mail.group', + 'default_res_id': group_pigs.id}).create({ + 'partner_ids': [(4, partner_carine.id)], 'send_mail': True}) + mail_invite.add_followers() # Test: Pigs followers should contain Admin and Bert - group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id) - follower_ids = [follower.id for follower in group_pigs.message_follower_ids] - self.assertEqual(set(follower_ids), set([self.partner_admin_id, partner_carine_id]), 'Pigs followers after invite is incorrect') - + self.assertEqual(group_pigs.message_follower_ids, partner_carine) # Test: partner must have been prepared for signup - partner_carine = self.res_partner.browse(cr, uid, partner_carine_id) self.assertTrue(partner_carine.signup_valid, 'partner has not been prepared for signup') self.assertTrue(base_url in partner_carine.signup_url, 'signup url is incorrect') - self.assertTrue(cr.dbname in partner_carine.signup_url, 'signup url is incorrect') + self.assertTrue(self.env.cr.dbname in partner_carine.signup_url, 'signup url is incorrect') self.assertTrue(partner_carine.signup_token in partner_carine.signup_url, 'signup url is incorrect') - # Test: (pretend to) send email and check subject, body - self.assertEqual(len(self._build_email_kwargs_list), 1, 'sent email number incorrect, should be only for Bert') - for sent_email in self._build_email_kwargs_list: - self.assertEqual(sent_email.get('subject'), 'Invitation to follow Discussion group: Pigs', - 'invite: subject of invitation email is incorrect') - self.assertIn('Administrator invited you to follow Discussion group document: Pigs', sent_email.get('body'), - 'invite: body of invitation email is incorrect') - self.assertIn(partner_carine.signup_token, sent_email.get('body'), - 'invite: body of invitation email does not contain signup token') + self.assertEqual(len(self._mails), 1, 'sent email number incorrect, should be only for Bert') + for sent_email in self._mails: + self.assertEqual( + sent_email.get('subject'), 'Invitation to follow Discussion group: Pigs', + 'invite: subject of invitation email is incorrect') + self.assertIn( + 'Administrator invited you to follow Discussion group document: Pigs', sent_email.get('body'), + 'invite: body of invitation email is incorrect') + self.assertIn( + partner_carine.signup_token, sent_email.get('body'), + 'invite: body of invitation email does not contain signup token') - def test_20_notification_url(self): - """ Tests designed to test the URL added in notification emails. """ - cr, uid, group_pigs = self.cr, self.uid, self.group_pigs - - # Partner data - partner_raoul = self.res_partner.browse(cr, uid, self.partner_raoul_id) - partner_bert_id = self.res_partner.create(cr, uid, {'name': 'bert'}) - partner_bert = self.res_partner.browse(cr, uid, partner_bert_id) + def test_mail_notification_url_partner_portal(self): # Mail data - mail_mail_id = self.mail_mail.create(cr, uid, {'state': 'exception'}) - mail = self.mail_mail.browse(cr, uid, mail_mail_id) - + mail = self.env['mail.mail'].create({'state': 'exception'}) # Test: link for nobody -> None - url = self.mail_mail._get_partner_access_link(cr, uid, mail) + url = self.env['mail.mail']._get_partner_access_link(mail) self.assertEqual(url, None, - 'notification email: mails not send to a specific partner should not have any URL') - + 'notification email: mails not send to a specific partner should not have any URL') # Test: link for partner -> signup URL - url = self.mail_mail._get_partner_access_link(cr, uid, mail, partner=partner_bert) - self.assertIn(partner_bert.signup_token, url, - 'notification email: mails send to a not-user partner should contain the signup token') - + url = self.env['mail.mail']._get_partner_access_link(mail, partner=self.partner_1) + self.assertIn(self.partner_1.signup_token, url, + 'notification email: mails send to a not-user partner should contain the signup token') # Test: link for user -> signin - url = self.mail_mail._get_partner_access_link(cr, uid, mail, partner=partner_raoul) + url = self.env['mail.mail']._get_partner_access_link(mail, partner=self.user_employee.partner_id) self.assertIn('action=mail.action_mail_redirect', url, - 'notification email: link should contain the redirect action') - self.assertIn('login=%s' % partner_raoul.user_ids[0].login, url, - 'notification email: link should contain the user login') + 'notification email: link should contain the redirect action') + self.assertIn('login=%s' % self.user_employee.login, url, + 'notification email: link should contain the user login') - @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') - def test_21_inbox_redirection(self): - """ Tests designed to test the inbox redirection of emails notification URLs. """ - cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs - model, act_id = self.ir_model_data.get_object_reference(cr, uid, 'mail', 'action_mail_inbox_feeds') - model, port_act_id = self.ir_model_data.get_object_reference(cr, uid, 'portal', 'action_mail_inbox_feeds_portal') + @mute_logger('openerp.addons.mail.mail_mail', 'openerp.models') + def test_inbox_redirection_portal(self): + group_pigs = self.group_pigs + port_act_id = self.ref('portal.action_mail_inbox_feeds_portal') # Data: post a message on pigs - msg_id = self.group_pigs.message_post(body='My body', partner_ids=[self.partner_bert_id, self.partner_chell_id], type='comment', subtype='mail.mt_comment') - - # No specific parameters -> should redirect to Inbox - action = self.mail_thread.message_redirect_action(cr, self.user_raoul_id, {'params': {}}) - self.assertEqual(action.get('type'), 'ir.actions.client', - 'URL redirection: action without parameters should redirect to client action Inbox') - self.assertEqual(action.get('id'), act_id, - 'URL redirection: action without parameters should redirect to client action Inbox') - - # Bert has read access to Pigs -> should redirect to form view of Pigs - action = self.mail_thread.message_redirect_action(cr, self.user_raoul_id, {'params': {'message_id': msg_id}}) - self.assertEqual(action.get('type'), 'ir.actions.act_window', - 'URL redirection: action with message_id for read-accredited user should redirect to Pigs') - self.assertEqual(action.get('res_id'), group_pigs.id, - 'URL redirection: action with message_id for read-accredited user should redirect to Pigs') - - # Bert has no read access to Pigs -> should redirect to Inbox - action = self.mail_thread.message_redirect_action(cr, self.user_bert_id, {'params': {'message_id': msg_id}}) - self.assertEqual(action.get('type'), 'ir.actions.client', - 'URL redirection: action without parameters should redirect to client action Inbox') - self.assertEqual(action.get('id'), act_id, - 'URL redirection: action without parameters should redirect to client action Inbox') - + msg_id = group_pigs.message_post(body='My body', partner_ids=[self.user_employee.partner_id.id, self.user_portal.partner_id.id], type='comment', subtype='mail.mt_comment') # Chell has no read access to pigs -> should redirect to Portal Inbox - action = self.mail_thread.message_redirect_action(cr, self.user_chell_id, {'params': {'message_id': msg_id}}) + action = self.env['mail.thread'].with_context({'params': {'message_id': msg_id}}).sudo(self.user_portal).message_redirect_action() self.assertEqual(action.get('type'), 'ir.actions.client', 'URL redirection: action without parameters should redirect to client action Inbox') self.assertEqual(action.get('id'), port_act_id, 'URL redirection: action without parameters should redirect to client action Inbox') - - def test_30_message_read(self): - cr, uid, group_port_id = self.cr, self.uid, self.group_port_id - - # Data: custom subtypes - mt_group_public_id = self.mail_message_subtype.create(cr, uid, {'name': 'group_public', 'description': 'Group changed'}) - self.ir_model_data.create(cr, uid, {'name': 'mt_group_public', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_group_public_id}) - # Data: post messages with various subtypes - msg1_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body1', type='comment', subtype='mail.mt_comment') - msg2_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body2', type='comment', subtype='mail.mt_group_public') - msg3_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body3', type='comment', subtype='mail.mt_comment') - msg4_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body4', type='comment') - # msg5_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body5', type='notification') - - # Do: Chell search messages: should not see internal notes (comment without subtype) - msg_ids = self.mail_message.search(cr, self.user_chell_id, [('model', '=', 'mail.group'), ('res_id', '=', group_port_id)]) - self.assertEqual(set(msg_ids), set([msg1_id, msg2_id, msg3_id]), - 'mail_message: portal user has access to messages he should not read') - - # Do: Chell read messages she can read - self.mail_message.read(cr, self.user_chell_id, msg_ids, ['body', 'type', 'subtype_id']) - - # Do: Chell read a message she should not be able to read - with self.assertRaises(AccessError): - self.mail_message.read(cr, self.user_chell_id, [msg4_id], ['body', 'type', 'subtype_id']) 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. -# -# 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 . -# -############################################################################## - -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. -# -# 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 . -# -############################################################################## 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: -X-Original-To: {email_to} -Delivered-To: {email_to} -To: {email_to} +X-Original-To: {to} +Delivered-To: {to} +To: {to} cc: {cc} Received: by mail1.openerp.com (Postfix, from userid 10002) id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST) @@ -53,120 +53,80 @@ Integrator at Agrolait""" class TestProjectFlow(TestProjectBase): @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') - def test_00_project_process(self): - """ Testing project management """ - cr, uid, user_projectuser_id, user_projectmanager_id, project_pigs_id = self.cr, self.uid, self.user_projectuser_id, self.user_projectmanager_id, self.project_pigs_id + def test_project_process_project_user(self): + self.assertRaises(AccessError, self.project_pigs.sudo(self.user_projectuser).set_template) - # ProjectUser: set project as template -> raise - self.assertRaises(AccessError, self.project_project.set_template, cr, user_projectuser_id, [project_pigs_id]) + def test_project_process_project_manager_set_template(self): + pigs = self.project_pigs.sudo(self.user_projectmanager) + pigs.set_template() + self.assertEqual(pigs.state, 'template') + self.assertEqual(len(pigs.tasks), 0, 'project: set_template: project tasks should have been set inactive') - # Other tests are done using a ProjectManager - project = self.project_project.browse(cr, user_projectmanager_id, project_pigs_id) - self.assertNotEqual(project.state, 'template', 'project: incorrect state, should not be a template') + # pigs.reset_project() + # self.assertEqual(pigs.state, 'open') + # self.assertEqual(len(pigs.tasks), 2, 'project: reset_project: project tasks should have been set active') - # Set test project as template - self.project_project.set_template(cr, user_projectmanager_id, [project_pigs_id]) - project.refresh() - self.assertEqual(project.state, 'template', 'project: set_template: project state should be template') - self.assertEqual(len(project.tasks), 0, 'project: set_template: project tasks should have been set inactive') - - # Duplicate template - new_template_act = self.project_project.duplicate_template(cr, user_projectmanager_id, [project_pigs_id]) - new_project = self.project_project.browse(cr, user_projectmanager_id, new_template_act['res_id']) - self.assertEqual(new_project.state, 'open', 'project: incorrect duplicate_template') + def test_project_process_project_manager_duplicate(self): + pigs = self.project_pigs.sudo(self.user_projectmanager) + new_template_act = pigs.duplicate_template() + new_project = self.env['project.project'].sudo(self.user_projectmanager).browse(new_template_act['res_id']) + self.assertEqual(new_project.state, 'open') self.assertEqual(len(new_project.tasks), 2, 'project: duplicating a project template should duplicate its tasks') - # Convert into real project - self.project_project.reset_project(cr, user_projectmanager_id, [project_pigs_id]) - project.refresh() - self.assertEqual(project.state, 'open', 'project: resetted project should be in open state') - self.assertEqual(len(project.tasks), 2, 'project: reset_project: project tasks should have been set active') - - # Put as pending - self.project_project.set_pending(cr, user_projectmanager_id, [project_pigs_id]) - project.refresh() - self.assertEqual(project.state, 'pending', 'project: should be in pending state') - + def test_project_process_project_manager_state(self): + pigs = self.project_pigs.sudo(self.user_projectmanager) + pigs.set_pending() + self.assertEqual(pigs.state, 'pending') # Re-open - self.project_project.set_open(cr, user_projectmanager_id, [project_pigs_id]) - project.refresh() - self.assertEqual(project.state, 'open', 'project: reopened project should be in open state') - + pigs.set_open() + self.assertEqual(pigs.state, 'open') # Close project - self.project_project.set_done(cr, user_projectmanager_id, [project_pigs_id]) - project.refresh() - self.assertEqual(project.state, 'close', 'project: closed project should be in close state') - + pigs.set_done() + self.assertEqual(pigs.state, 'close') # Re-open - self.project_project.set_open(cr, user_projectmanager_id, [project_pigs_id]) - project.refresh() - + pigs.set_open() # Re-convert into a template and schedule tasks - self.project_project.set_template(cr, user_projectmanager_id, [project_pigs_id]) - self.project_project.schedule_tasks(cr, user_projectmanager_id, [project_pigs_id]) - + pigs.set_template() + pigs.schedule_tasks() # Copy the project - new_project_id = self.project_project.copy(cr, user_projectmanager_id, project_pigs_id) - new_project = self.project_project.browse(cr, user_projectmanager_id, new_project_id) + new_project = pigs.copy() self.assertEqual(len(new_project.tasks), 2, 'project: copied project should have copied task') - # Cancel the project - self.project_project.set_cancel(cr, user_projectmanager_id, [project_pigs_id]) - self.assertEqual(project.state, 'cancelled', 'project: cancelled project should be in cancel state') - - def test_10_task_process(self): - """ Testing task creation and management """ - cr, uid, user_projectuser_id, user_projectmanager_id, project_pigs_id = self.cr, self.uid, self.user_projectuser_id, self.user_projectmanager_id, self.project_pigs_id - - # create new partner - self.partner_id = self.registry('res.partner').create(cr, uid, { - 'name': 'Pigs', - 'email': 'otherid@gmail.com', - }, {'mail_create_nolog': True}) - - def format_and_process(template, email_to='project+pigs@mydomain.com, other@gmail.com', cc='otherid@gmail.com', subject='Frogs', - email_from='Patrick Ratatouille ', - 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. -# -# 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 . -# -############################################################################## -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. -# -# 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 . -# -############################################################################## 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')