diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 97608c0d080..88058f5f709 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -90,7 +90,6 @@ class mail_thread(osv.AbstractModel): # :param obj: is a browse_record # :param function lambda: returns whether the tracking should record using this subtype _track = {} - _TRACK_TEMPLATE = """ %if message_description: ${message_description} @@ -249,7 +248,11 @@ class mail_thread(osv.AbstractModel): #------------------------------------------------------ def create(self, cr, uid, values, context=None): - """ Override to subscribe the current user. """ + """ Chatter override : + - subscribe uid + - subscribe followers of parent + - log a creation message + """ if context is None: context = {} thread_id = super(mail_thread, self).create(cr, uid, values, context=context) @@ -259,8 +262,9 @@ class mail_thread(osv.AbstractModel): self.message_subscribe_users(cr, uid, [thread_id], [uid], context=context) self.message_subscribe_from_parent(cr, uid, [thread_id], context=context) - # automatic logging - self.message_post(cr, uid, thread_id, body='Document created.', context=context) + # automatic logging unless asked not to (mainly for various testing purpose) + if not context.get('mail_nolog'): + self.message_post(cr, uid, thread_id, body='Document created.', context=context) return thread_id def write(self, cr, uid, ids, values, context=None): @@ -306,14 +310,15 @@ class mail_thread(osv.AbstractModel): """ lst = [] for name, column_info in self._all_columns.items(): - vis = getattr(column_info.column, 'track_visibility', False) - if (vis==2) or ((vis==1) and (name in updated_fields)) or (name in self._track): + visibility = getattr(column_info.column, 'track_visibility', False) + if visibility == 2 or (visibility == 1 and name in updated_fields) or name in self._track: lst.append(name) + if not lst: + return lst return self.fields_get(cr, uid, lst, context=context) def message_track(self, cr, uid, ids, tracked_fields, initial_values, context=None): - if not tracked_fields: - return True + def convert_for_display(value, field_obj): if not value: return '' @@ -323,29 +328,32 @@ class mail_thread(osv.AbstractModel): return dict(field_obj['selection'])[value] return value + if not tracked_fields: + return True + for record in self.read(cr, uid, ids, tracked_fields.keys(), context=context): initial = initial_values[record['id']] - changes = [] tracked_values = {} + # generate tracked_values data structure: {'col_name': {col_info, new_value, old_value}} for col_name, col_info in tracked_fields.items(): - if record[col_name] == initial[col_name] and (getattr(self._all_columns[col_name].column, 'track_visibility', 0) == 2): + if record[col_name] == initial[col_name] and getattr(self._all_columns[col_name].column, 'track_visibility', 0) == 2: tracked_values[col_name] = dict(col_info=col_info['string'], new_value=convert_for_display(record[col_name], col_info)) - elif record[col_name] != initial[col_name] and (getattr(self._all_columns[col_name].column, 'track_visibility', 0) == 1): - tracked_values[col_name] = dict(col_info=col_info['string'], - old_value=convert_for_display(initial[col_name], col_info), + elif record[col_name] != initial[col_name] and getattr(self._all_columns[col_name].column, 'track_visibility', 0) in [1, 2]: + tracked_values[col_name] = dict(col_info=col_info['string'], + old_value=convert_for_display(initial[col_name], col_info), new_value=convert_for_display(record[col_name], col_info)) changes.append(col_name) if not changes: continue # find subtypes and post messages or log if no subtype found - subtypes = [] for field, track_info in self._track.items(): - if field not in changes: continue + if field not in changes: + continue for subtype, method in track_info.items(): if method(self, cr, uid, record, context): subtypes.append(subtype) @@ -353,8 +361,8 @@ class mail_thread(osv.AbstractModel): posted = False for subtype in subtypes: try: - subtype_rec = self.pool.get('ir.model.data').get_object(cr, uid, *subtype.split('.')) - except ValueError, e: + subtype_rec = self.pool.get('ir.model.data').get_object(cr, uid, subtype.split('.')[0], subtype.split('.')[1]) + except ValueError: continue message = MakoTemplate(self._TRACK_TEMPLATE).render_unicode(message_description=subtype_rec.description, tracked_values=tracked_values) self.message_post(cr, uid, record['id'], body=message, subtype=subtype, context=context) @@ -642,9 +650,9 @@ class mail_thread(osv.AbstractModel): alternative = (message.get_content_type() == 'multipart/alternative') for part in message.walk(): if part.get_content_maintype() == 'multipart': - continue # skip container - filename = part.get_filename() # None if normal part - encoding = part.get_content_charset() # None if attachment + continue # skip container + filename = part.get_filename() # None if normal part + encoding = part.get_content_charset() # None if attachment # 1) Explicit Attachments -> attachments if filename or part.get('content-disposition', '').strip().startswith('attachment'): attachments.append((filename or 'attachment', part.get_payload(decode=True))) diff --git a/addons/mail/tests/test_mail_base.py b/addons/mail/tests/test_mail_base.py index b71e31ed872..ca705559158 100644 --- a/addons/mail/tests/test_mail_base.py +++ b/addons/mail/tests/test_mail_base.py @@ -82,7 +82,8 @@ class TestMailBase(common.TransactionCase): # 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 !'}) + {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'}, + {'mail_nolog': True}) self.group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id) def tearDown(self): diff --git a/addons/mail/tests/test_mail_features.py b/addons/mail/tests/test_mail_features.py index 8a5dc4fb690..600f84c0ebb 100644 --- a/addons/mail/tests/test_mail_features.py +++ b/addons/mail/tests/test_mail_features.py @@ -19,8 +19,6 @@ # ############################################################################## -from openerp import tools - from openerp.addons.mail.tests.test_mail_base import TestMailBase from openerp.tools.mail import html_sanitize, append_content_to_html @@ -121,18 +119,18 @@ class test_mail(TestMailBase): # Previously-created group can be emailed now - it should have an implicit alias group+frogs@... frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) group_messages = frog_group.message_ids - self.assertTrue(len(group_messages) == 1, 'New group should only have the original message') + self.assertTrue(len(group_messages) == 2, 'New group should only have the original message + creation log') mail_frog_news = MAIL_TEMPLATE.format(to='Friendly Frogs ', subject='news', extra='') self.mail_thread.message_process(cr, uid, None, mail_frog_news) frog_group.refresh() - self.assertTrue(len(frog_group.message_ids) == 2, 'Group should contain 2 messages now') + self.assertTrue(len(frog_group.message_ids) == 3, 'Group should contain 3 messages now') # Even with a wrong destination, a reply should end up in the correct thread mail_reply = MAIL_TEMPLATE.format(to='erroneous@example.com>', subject='Re: news', extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id) self.mail_thread.message_process(cr, uid, None, mail_reply) frog_group.refresh() - self.assertTrue(len(frog_group.message_ids) == 3, 'Group should contain 3 messages now') + self.assertTrue(len(frog_group.message_ids) == 4, 'Group should contain 4 messages now') # No model passed and no matching alias must raise mail_spam = MAIL_TEMPLATE.format(to='noone@example.com', subject='spam', extra='') @@ -206,7 +204,7 @@ class test_mail(TestMailBase): # 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'}) + {'name': 'Dummy group'}, {'mail_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, @@ -445,7 +443,7 @@ class test_mail(TestMailBase): cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs mail_compose = self.registry('mail.compose.message') self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'}) - group_bird_id = self.mail_group.create(cr, uid, {'name': 'Bird', 'description': 'Bird resistance'}) + group_bird_id = self.mail_group.create(cr, uid, {'name': 'Bird', 'description': 'Bird resistance'}, {'mail_nolog': True}) group_bird = self.mail_group.browse(cr, uid, group_bird_id) # Mail data @@ -604,19 +602,19 @@ class test_mail(TestMailBase): # 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.group', 'module': 'mail', 'res_id': mt_private_id}) + 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.group', 'module': 'mail', 'res_id': mt_name_supername_id}) + 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_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.group', 'module': 'mail', 'res_id': mt_group_public_id}) + self.ir_model_data.create(cr, uid, {'name': 'mt_group_public', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_group_public_id}) # Data: alter mail_group model for testing purposes (test on classic, selection and many2one fields) self.mail_group._track = { 'public': { - 'mail.mt_private': lambda self, cr, uid, obj, ctx=None: obj.public == 'private', + 'mail.mt_private': lambda self, cr, uid, obj, ctx=None: obj['public'] == 'private', }, 'name': { - 'mail.mt_name_supername': lambda self, cr, uid, obj, ctx=None: obj.name == 'supername', + 'mail.mt_name_supername': lambda self, cr, uid, obj, ctx=None: obj['name'] == 'supername', }, 'group_public_id': { 'mail.mt_group_public': lambda self, cr, uid, obj, ctx=None: True, @@ -625,9 +623,9 @@ class test_mail(TestMailBase): public_col = self.mail_group._columns.get('public') name_col = self.mail_group._columns.get('name') group_public_col = self.mail_group._columns.get('group_public_id') - public_col._track_visibility = 1 - name_col._track_visibility = 2 - group_public_col._track_visibility = 1 + public_col.track_visibility = 1 + name_col.track_visibility = 2 + group_public_col.track_visibility = 1 # 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'}) @@ -636,7 +634,7 @@ class test_mail(TestMailBase): # Test: first produced message: no subtype, name change tracked last_msg = self.group_pigs.message_ids[-1] self.assertFalse(last_msg.subtype_id, 'tracked: message should not have been linked to a subtype') - self.assertIn('SelectedGroupOnly->Public', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect') + self.assertIn('SelectedGroupOnly→Public', _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 @@ -647,13 +645,13 @@ class test_mail(TestMailBase): 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('Pigs->supername', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect') + self.assertIn('Pigs→supername', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect') # Test: second produced message: mt_name_supername last_msg = self.group_pigs.message_ids[-3] self.assertEqual(last_msg.subtype_id.id, mt_name_supername_id, 'tracked: message should be linked to mt_name_supername subtype') self.assertIn('Supername name', last_msg.body, 'tracked: message body does not hold the subtype description') - self.assertIn('Public->Private', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect') - self.assertIn('Pigs->supername', _strip_string_spaces(last_msg.body), 'tracked feature: message body does not hold always tracked field') + self.assertIn('Public→Private', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect') + self.assertIn('Pigs→supername', _strip_string_spaces(last_msg.body), 'tracked feature: message body does not hold always tracked field') # 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}) @@ -663,8 +661,8 @@ class test_mail(TestMailBase): last_msg = self.group_pigs.message_ids[-4] self.assertEqual(last_msg.subtype_id.id, mt_group_public_id, 'tracked: message should not be linked to any subtype') self.assertIn('Group changed', last_msg.body, 'tracked: message body does not hold the subtype description') - self.assertIn('Private->Public', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold changed tracked field') - self.assertIn('HumanResources/Employee->Administration/Settings', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold always tracked field') + self.assertIn('Private→Public', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold changed tracked field') + self.assertIn('HumanResources/Employee→Administration/Settings', _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'}) @@ -672,7 +670,7 @@ class test_mail(TestMailBase): self.assertEqual(len(self.group_pigs.message_ids), 4, 'tracked: No message should have been produced') # Data: removed changes - public_col._track_visibility = False - name_col._track_visibility = False - group_public_col._track_visibility = False + public_col.track_visibility = False + name_col.track_visibility = False + group_public_col.track_visibility = False self.mail_group._track = {}