[IMP] mail_message: added the right to reply to a message wes received even if we cannot see the related document.
bzr revid: tde@openerp.com-20121212160634-umbiq2erwijm2d20
This commit is contained in:
parent
179f525dc7
commit
f1ee7f1ad9
|
@ -608,55 +608,73 @@ class mail_message(osv.Model):
|
|||
- uid have read access to the related document if model, res_id
|
||||
- otherwise: raise
|
||||
- create: if
|
||||
- no model, no res_id, I create a private message
|
||||
- no model, no res_id, I create a private message OR
|
||||
- pid in message_follower_ids if model, res_id OR
|
||||
- mail_notification (parent_id.id, pid) exists, uid has been notified of the parent, OR
|
||||
- uid have write access on the related document if model, res_id, OR
|
||||
- otherwise: raise
|
||||
- write: if
|
||||
- author_id == pid, uid is the author, OR
|
||||
- uid has write access on the related document if model, res_id
|
||||
- Otherwise: raise
|
||||
- otherwise: raise
|
||||
- unlink: if
|
||||
- uid has write access on the related document if model, res_id
|
||||
- Otherwise: raise
|
||||
- otherwise: raise
|
||||
"""
|
||||
def _generate_model_record_ids(msg_val, msg_ids=[]):
|
||||
""" :param model_record_ids: {'model': {'res_id': (msg_id, msg_id)}, ... }
|
||||
:param message_values: {'msg_id': {'model': .., 'res_id': .., 'author_id': ..}}
|
||||
"""
|
||||
model_record_ids = {}
|
||||
for id in msg_ids:
|
||||
if msg_val[id]['model'] and msg_val[id]['res_id']:
|
||||
model_record_ids.setdefault(msg_val[id]['model'], dict()).setdefault(msg_val[id]['res_id'], set()).add(msg_val[id]['res_id'])
|
||||
return model_record_ids
|
||||
|
||||
if uid == SUPERUSER_ID:
|
||||
return
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
not_obj = self.pool.get('mail.notification')
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0]
|
||||
|
||||
# Read mail_message.ids to have their values
|
||||
message_values = dict.fromkeys(ids)
|
||||
model_record_ids = {}
|
||||
cr.execute('SELECT DISTINCT id, model, res_id, author_id FROM "%s" WHERE id = ANY (%%s)' % self._table, (ids,))
|
||||
for id, rmod, rid, author_id in cr.fetchall():
|
||||
message_values[id] = {'res_model': rmod, 'res_id': rid, 'author_id': author_id}
|
||||
if rmod:
|
||||
model_record_ids.setdefault(rmod, dict()).setdefault(rid, set()).add(id)
|
||||
cr.execute('SELECT DISTINCT id, model, res_id, author_id, parent_id FROM "%s" WHERE id = ANY (%%s)' % self._table, (ids,))
|
||||
for id, rmod, rid, author_id, parent_id in cr.fetchall():
|
||||
message_values[id] = {'model': rmod, 'res_id': rid, 'author_id': author_id, 'parent_id': parent_id}
|
||||
|
||||
# Author condition, for read and create (private message) -> could become an ir.rule, but not till we do not have a many2one variable field
|
||||
# Author condition (READ, WRITE, CREATE (private)) -> could become an ir.rule ?
|
||||
author_ids = []
|
||||
if operation == 'read' or operation == 'write':
|
||||
author_ids = [mid for mid, message in message_values.iteritems()
|
||||
if message.get('author_id') and message.get('author_id') == partner_id]
|
||||
elif operation == 'create':
|
||||
author_ids = [mid for mid, message in message_values.iteritems()
|
||||
if not message.get('model') and not message.get('res_id')]
|
||||
else:
|
||||
author_ids = []
|
||||
|
||||
# Parent condition, for create (check for received notifications for the created message parent)
|
||||
notified_ids = []
|
||||
if operation == 'create':
|
||||
parent_ids = [message.get('parent_id') for mid, message in message_values.iteritems()
|
||||
if message.get('parent_id')]
|
||||
not_ids = not_obj.search(cr, SUPERUSER_ID, [('message_id.id', 'in', parent_ids), ('partner_id', '=', partner_id)], context=context)
|
||||
not_parent_ids = [notif.message_id.id for notif in not_obj.browse(cr, SUPERUSER_ID, not_ids, context=context)]
|
||||
notified_ids += [mid for mid, message in message_values.iteritems()
|
||||
if message.get('parent_id') in not_parent_ids]
|
||||
|
||||
# Notification condition, for read (check for received notifications and create (in message_follower_ids)) -> could become an ir.rule, but not till we do not have a many2one variable field
|
||||
other_ids = set(ids).difference(set(author_ids), set(notified_ids))
|
||||
model_record_ids = _generate_model_record_ids(message_values, other_ids)
|
||||
if operation == 'read':
|
||||
not_obj = self.pool.get('mail.notification')
|
||||
not_ids = not_obj.search(cr, SUPERUSER_ID, [
|
||||
('partner_id', '=', partner_id),
|
||||
('message_id', 'in', ids),
|
||||
], context=context)
|
||||
notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, SUPERUSER_ID, not_ids, context=context)]
|
||||
elif operation == 'create':
|
||||
notified_ids = []
|
||||
for doc_model, doc_dict in model_record_ids.items():
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [
|
||||
('res_model', '=', doc_model),
|
||||
('res_id', 'in', list(doc_dict.keys())),
|
||||
|
@ -664,22 +682,15 @@ class mail_message(osv.Model):
|
|||
], context=context)
|
||||
fol_mids = [follower.res_id for follower in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)]
|
||||
notified_ids += [mid for mid, message in message_values.iteritems()
|
||||
if message.get('res_model') == doc_model and message.get('res_id') in fol_mids]
|
||||
else:
|
||||
notified_ids = []
|
||||
|
||||
# Calculate remaining ids, and related model/res_ids
|
||||
model_record_ids = {}
|
||||
other_ids = set(ids).difference(set(author_ids), set(notified_ids))
|
||||
for id in other_ids:
|
||||
if message_values[id]['res_model']:
|
||||
model_record_ids.setdefault(message_values[id]['res_model'], set()).add(message_values[id]['res_id'])
|
||||
if message.get('model') == doc_model and message.get('res_id') in fol_mids]
|
||||
|
||||
# CRUD: Access rights related to the document
|
||||
other_ids = other_ids.difference(set(notified_ids))
|
||||
model_record_ids = _generate_model_record_ids(message_values, other_ids)
|
||||
document_related_ids = []
|
||||
for model, mids in model_record_ids.items():
|
||||
for model, doc_dict in model_record_ids.items():
|
||||
model_obj = self.pool.get(model)
|
||||
mids = model_obj.exists(cr, uid, mids)
|
||||
mids = model_obj.exists(cr, uid, doc_dict.keys())
|
||||
if operation in ['create', 'write', 'unlink']:
|
||||
model_obj.check_access_rights(cr, uid, 'write')
|
||||
model_obj.check_access_rule(cr, uid, mids, 'write', context=context)
|
||||
|
@ -687,10 +698,10 @@ class mail_message(osv.Model):
|
|||
model_obj.check_access_rights(cr, uid, operation)
|
||||
model_obj.check_access_rule(cr, uid, mids, operation, context=context)
|
||||
document_related_ids += [mid for mid, message in message_values.iteritems()
|
||||
if message.get('res_model') == model and message.get('res_id') in mids]
|
||||
if message.get('model') == model and message.get('res_id') in mids]
|
||||
|
||||
# Calculate remaining ids: if not void, raise an error
|
||||
other_ids = other_ids - set(document_related_ids)
|
||||
other_ids = other_ids.difference(set(document_related_ids))
|
||||
if not other_ids:
|
||||
return
|
||||
raise orm.except_orm(_('Access Denied'),
|
||||
|
|
|
@ -123,7 +123,8 @@ class test_mail_access_rights(TestMailBase):
|
|||
user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id
|
||||
|
||||
# Prepare groups: Pigs (employee), Jobs (public)
|
||||
self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message')
|
||||
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')
|
||||
|
||||
# prepare an attachment
|
||||
attachment_id = self.ir_attachment.create(cr, uid, {'datas': 'My attachment'.encode('base64'), 'name': 'doc.txt', 'datas_fname': 'doc.txt'})
|
||||
|
@ -184,11 +185,20 @@ class test_mail_access_rights(TestMailBase):
|
|||
# Do: Bert create a private message -> ko, no creation rights
|
||||
self.assertRaises(except_orm, self.mail_message.create,
|
||||
cr, user_bert_id, {'body': 'Test'})
|
||||
|
||||
# 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'})
|
||||
# Do: Raoul creates a message on Priv -> ko, no write access to the related document
|
||||
self.assertRaises(except_orm, 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
|
||||
self.assertRaises(except_orm, self.mail_message.create,
|
||||
cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id})
|
||||
# Do: Raoul creates a reply to a message on Priv-> ok if has received parent
|
||||
self.mail_notification.create(cr, uid, {'message_id': priv_msg_id, 'partner_id': self.partner_raoul_id})
|
||||
self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id})
|
||||
|
||||
def test_20_message_set_star(self):
|
||||
""" Tests for starring messages and its related access rights """
|
||||
|
@ -326,6 +336,11 @@ class test_mail_access_rights(TestMailBase):
|
|||
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(except_orm):
|
||||
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
|
||||
# ----------------------------------------
|
||||
|
@ -350,3 +365,11 @@ class test_mail_access_rights(TestMailBase):
|
|||
{'subject': 'Subject', 'body': 'Body text'},
|
||||
{'default_composition_mode': 'reply', 'default_parent_id': pigs_msg_id})
|
||||
mail_compose.send_mail(cr, user_raoul_id, [compose_id])
|
||||
|
||||
# Do: Raoul writes on its own profile, ok because follower of its partner
|
||||
self.res_users.message_post(cr, user_raoul_id, user_raoul_id, body='I love Raoul')
|
||||
self.res_partner.message_post(cr, user_raoul_id, partner_raoul_id, body='I love Raoul')
|
||||
compose_id = mail_compose.create(cr, user_raoul_id,
|
||||
{'subject': 'Subject', 'body': 'Body text', 'partner_ids': []},
|
||||
{'default_composition_mode': 'comment', 'default_model': 'res.users', 'default_res_id': self.user_raoul_id})
|
||||
mail_compose.send_mail(cr, user_raoul_id, [compose_id])
|
||||
|
|
Loading…
Reference in New Issue