diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 4e35f3fd197..6e5f594354a 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -29,7 +29,6 @@ import time import tools import xmlrpclib -from email.utils import parsedate from email.message import Message from mail_message import decode from osv import osv, fields @@ -42,24 +41,20 @@ def decode_header(message, header, separator=' '): return separator.join(map(decode,message.get_all(header, []))) class many2many_reference(fields.many2many): - """ many2many_reference is an override of fields.many2many. It manages - many2many-like table where one id is given by two fields, res_model - and res_id. - """ + """ many2many_reference manages many2many fields where one id is found + by a reference-like key (a char column in addition to the foreign id). + The reference_column attribute on the many2many fields is used; + if not defined, ``res_model`` is used. """ def _get_query_and_where_params(self, cr, model, ids, values, where_params): - """ Add in where: - - ``mail_followers``.res_model = 'crm.lead' - """ - # reference column name: given by attribute or res_model - ref_col_name = self.ref_col_name if self.ref_col_name else 'res_model' - values.update({'ref_col_name': ref_col_name, 'ref_col_value': model._name}) - + """ Add in where condition like mail_followers.res_model = 'crm.lead' """ + reference_column = self.reference_column if self.reference_column else 'res_model' + values.update(reference_column=reference_column, reference_value=model._name) query = 'SELECT %(rel)s.%(id2)s, %(rel)s.%(id1)s \ FROM %(rel)s, %(from_c)s \ WHERE %(rel)s.%(id1)s IN %%s \ AND %(rel)s.%(id2)s = %(tbl)s.id \ - AND %(rel)s.%(ref_col_name)s = \'%(ref_col_value)s\' \ + AND %(rel)s.%(reference_column)s = \'%(reference_value)s\' \ %(where_c)s \ %(order_by)s \ %(limit)s \ @@ -68,41 +63,41 @@ class many2many_reference(fields.many2many): return query, where_params def set(self, cr, model, id, name, values, user=None, context=None): - """ Override to add the res_model field in queries. """ + """ Override to add the reference field in queries. """ if not values: return rel, id1, id2 = self._sql_names(model) obj = model.pool.get(self._obj) # reference column name: given by attribute or res_model - ref_col_name = self.ref_col_name if self.ref_col_name else 'res_model' + reference_column = self.reference_column if self.reference_column else 'res_model' for act in values: if not (isinstance(act, list) or isinstance(act, tuple)) or not act: continue if act[0] == 0: idnew = obj.create(cr, user, act[2], context=context) - cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+','+ref_col_name+') VALUES (%s,%s,%s)', (id, idnew, model._name)) + cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+','+reference_column+') VALUES (%s,%s,%s)', (id, idnew, model._name)) elif act[0] == 3: - cr.execute('DELETE FROM '+rel+' WHERE '+id1+'=%s AND '+id2+'=%s AND '+ref_col_name+'=%s', (id, act[1], model._name)) + cr.execute('DELETE FROM '+rel+' WHERE '+id1+'=%s AND '+id2+'=%s AND '+reference_column+'=%s', (id, act[1], model._name)) elif act[0] == 4: # following queries are in the same transaction - so should be relatively safe - cr.execute('SELECT 1 FROM '+rel+' WHERE '+id1+'=%s AND '+id2+'=%s AND '+ref_col_name+'=%s', (id, act[1], model._name)) + cr.execute('SELECT 1 FROM '+rel+' WHERE '+id1+'=%s AND '+id2+'=%s AND '+reference_column+'=%s', (id, act[1], model._name)) if not cr.fetchone(): - cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+','+ref_col_name+') VALUES (%s,%s,%s)', (id, act[1], model._name)) + cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+','+reference_column+') VALUES (%s,%s,%s)', (id, act[1], model._name)) elif act[0] == 5: - cr.execute('delete from '+rel+' where '+id1+' = %s AND '+ref_col_name+'=%s', (id, model._name)) + cr.execute('delete from '+rel+' where '+id1+' = %s AND '+reference_column+'=%s', (id, model._name)) elif act[0] == 6: d1, d2,tables = obj.pool.get('ir.rule').domain_get(cr, user, obj._name, context=context) if d1: d1 = ' and ' + ' and '.join(d1) else: d1 = '' - cr.execute('DELETE FROM '+rel+' WHERE '+id1+'=%s AND '+ref_col_name+'=%s AND '+id2+' IN (SELECT '+rel+'.'+id2+' FROM '+rel+', '+','.join(tables)+' WHERE '+rel+'.'+id1+'=%s AND '+rel+'.'+id2+' = '+obj._table+'.id '+ d1 +')', [id, model._name, id]+d2) + cr.execute('DELETE FROM '+rel+' WHERE '+id1+'=%s AND '+reference_column+'=%s AND '+id2+' IN (SELECT '+rel+'.'+id2+' FROM '+rel+', '+','.join(tables)+' WHERE '+rel+'.'+id1+'=%s AND '+rel+'.'+id2+' = '+obj._table+'.id '+ d1 +')', [id, model._name, id]+d2) for act_nbr in act[2]: - cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+','+ref_col_name+') VALUES (%s,%s,%s)', (id, act_nbr, model._name)) + cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+','+reference_column+') VALUES (%s,%s,%s)', (id, act_nbr, model._name)) # cases 1, 2: performs write and unlink -> default implementation is ok else: return super(many2many_reference, self).set(cr, model, id, name, values, user, context) -class mail_thread(osv.Model): +class mail_thread(osv.AbstractModel): ''' mail_thread model is meant to be inherited by any model that needs to act as a discussion topic on which messages can be attached. Public methods are prefixed with ``message_`` in order to avoid name @@ -161,7 +156,7 @@ class mail_thread(osv.Model): type='boolean', string='Is a Follower', multi='_get_message_data'), 'message_follower_ids': many2many_reference('res.partner', 'mail_followers', 'res_id', 'partner_id', - ref_col_name='res_model', string='Followers'), + reference_column='res_model', string='Followers'), 'message_comment_ids': fields.one2many('mail.message', 'res_id', domain=lambda self: [('model','=',self._name),('type','in',('comment','email'))], string='Related Messages',