[FIX] mail: replace buggy many2many_reference field by function field; this fixes the search on field mail_follower_ids
bzr revid: rco@openerp.com-20121008151234-9oovjatffaw48k1d
This commit is contained in:
+58
-60
@@ -39,63 +39,6 @@ _logger = logging.getLogger(__name__)
|
||||
def decode_header(message, header, separator=' '):
|
||||
return separator.join(map(decode, message.get_all(header, [])))
|
||||
|
||||
class many2many_reference(fields.many2many):
|
||||
""" 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 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.%(reference_column)s = \'%(reference_value)s\' \
|
||||
%(where_c)s \
|
||||
%(order_by)s \
|
||||
%(limit)s \
|
||||
OFFSET %(offset)d' \
|
||||
% values
|
||||
return query, where_params
|
||||
|
||||
def set(self, cr, model, id, name, values, user=None, context=None):
|
||||
""" 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
|
||||
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+','+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 '+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 '+reference_column+'=%s', (id, act[1], model._name))
|
||||
if not cr.fetchone():
|
||||
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 '+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 '+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+','+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.AbstractModel):
|
||||
''' mail_thread model is meant to be inherited by any model that needs to
|
||||
@@ -186,6 +129,62 @@ class mail_thread(osv.AbstractModel):
|
||||
res[notif.message_id.res_id] = True
|
||||
return [('id', 'in', res.keys())]
|
||||
|
||||
def _get_followers(self, cr, uid, ids, name, arg, context=None):
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('res_id', 'in', ids)])
|
||||
res = dict((res_id, []) for res_id in ids)
|
||||
for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids):
|
||||
res[fol.res_id].append(fol.partner_id.id)
|
||||
return res
|
||||
|
||||
def _set_followers(self, cr, uid, id, name, value, arg, context=None):
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
|
||||
# read the old set of followers, and determine the new set of followers
|
||||
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('res_id', '=', id)])
|
||||
old = set(fol.partner_id.id for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids))
|
||||
new = set(old)
|
||||
|
||||
for command in value:
|
||||
if isinstance(command, (int, long)):
|
||||
new.add(command)
|
||||
elif command[0] == 0:
|
||||
new.add(partner_obj.create(cr, uid, command[2], context=context))
|
||||
elif command[0] == 1:
|
||||
partner_obj.write(cr, uid, [command[1]], command[2], context=context)
|
||||
new.add(command[1])
|
||||
elif command[0] == 2:
|
||||
partner_obj.unlink(cr, uid, [command[1]], context=context)
|
||||
new.discard(command[1])
|
||||
elif command[0] == 3:
|
||||
new.discard(command[1])
|
||||
elif command[0] == 4:
|
||||
new.add(command[1])
|
||||
elif command[0] == 5:
|
||||
new.clear()
|
||||
elif command[0] == 6:
|
||||
new = set(command[2])
|
||||
|
||||
# remove partners that are no longer followers
|
||||
fol_ids = fol_obj.search(cr, SUPERUSER_ID,
|
||||
[('res_model', '=', self._name), ('res_id', '=', id), ('partner_id', 'not in', list(new))])
|
||||
fol_obj.unlink(cr, SUPERUSER_ID, fol_ids)
|
||||
|
||||
# add new followers
|
||||
for partner_id in new - old:
|
||||
fol_obj.create(cr, SUPERUSER_ID, {'res_model': self._name, 'res_id': id, 'partner_id': partner_id})
|
||||
|
||||
def _search_followers(self, cr, uid, obj, name, args, context):
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
res = []
|
||||
for field, operator, value in args:
|
||||
assert field == name
|
||||
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('partner_id', operator, value)])
|
||||
res_ids = [fol.res_id for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids)]
|
||||
res.append(('id', 'in', res_ids))
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'message_is_follower': fields.function(_get_subscription_data,
|
||||
type='boolean', string='Is a Follower', multi='_get_subscription_data,'),
|
||||
@@ -194,9 +193,8 @@ class mail_thread(osv.AbstractModel):
|
||||
help="Holds data about the subtypes. The content of this field "\
|
||||
"is a structure holding the current model subtypes, and the "\
|
||||
"current document followed subtypes."),
|
||||
'message_follower_ids': many2many_reference('res.partner',
|
||||
'mail_followers', 'res_id', 'partner_id',
|
||||
reference_column='res_model', string='Followers'),
|
||||
'message_follower_ids': fields.function(_get_followers, fnct_inv=_set_followers,
|
||||
fnct_search=_search_followers, type='many2many', obj='res.partner', string='Followers'),
|
||||
'message_comment_ids': fields.one2many('mail.message', 'res_id',
|
||||
domain=lambda self: [('model', '=', self._name), ('type', 'in', ('comment', 'email'))],
|
||||
string='Comments and emails',
|
||||
|
||||
@@ -194,7 +194,7 @@ class test_mail(TestMailMockups):
|
||||
'plaintext mail incorrectly parsed')
|
||||
|
||||
def test_10_many2many_reference_field(self):
|
||||
""" Tests designed for the many2many_reference field (follower_ids).
|
||||
""" 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 = self.cr, self.uid
|
||||
|
||||
Reference in New Issue
Block a user