+
diff --git a/addons/mail/mail_mail.py b/addons/mail/mail_mail.py
index 6bbfa9bc30e..e9a569a8192 100644
--- a/addons/mail/mail_mail.py
+++ b/addons/mail/mail_mail.py
@@ -19,13 +19,12 @@
#
##############################################################################
-# import ast
import base64
import logging
import tools
-from osv import osv
-from osv import fields
+from openerp import SUPERUSER_ID
+from osv import osv, fields
from tools.translate import _
_logger = logging.getLogger(__name__)
@@ -134,7 +133,8 @@ class mail_mail(osv.Model):
:return: True
"""
if mail.auto_delete:
- mail.unlink()
+ # done with SUPERUSER_ID to avoid giving large unlink access rights
+ self.unlink(cr, SUPERUSER_ID, [mail.id], context=context)
return True
def send_get_mail_subject(self, cr, uid, mail, force=False, partner=None, context=None):
diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index 1d5d85e36e0..7d9c7b3085f 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -24,8 +24,9 @@ import openerp
import tools
from email.header import decode_header
+from openerp import SUPERUSER_ID
from operator import itemgetter
-from osv import osv, fields
+from osv import osv, orm, fields
from tools.translate import _
_logger = logging.getLogger(__name__)
@@ -62,14 +63,14 @@ class mail_message(osv.Model):
continue
try:
result[message.id] = self._shorten_name(self.pool.get(message.model).name_get(cr, uid, [message.res_id], context=context)[0][1])
- except openerp.exceptions.AccessDenied, e:
+ except (orm.except_orm, osv.except_osv):
pass
return result
def _get_unread(self, cr, uid, ids, name, arg, context=None):
""" Compute if the message is unread by the current user. """
res = dict((id, {'unread': False}) for id in ids)
- partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
+ partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
notif_obj = self.pool.get('mail.notification')
notif_ids = notif_obj.search(cr, uid, [
('partner_id', 'in', [partner_id]),
@@ -87,7 +88,7 @@ class mail_message(osv.Model):
read_cond = '(read = false or read is null)'
else:
read_cond = 'read = true'
- partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
+ partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
cr.execute("SELECT message_id FROM mail_notification "\
"WHERE partner_id = %%s AND %s" % read_cond,
(partner_id,))
@@ -140,7 +141,8 @@ class mail_message(osv.Model):
return []
def _get_default_author(self, cr, uid, context=None):
- return self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
+ # remove context to avoid possible hack in browse with superadmin using context keys that could trigger a specific behavior
+ return self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=None).partner_id.id
_defaults = {
'type': 'email',
@@ -154,16 +156,17 @@ class mail_message(osv.Model):
#------------------------------------------------------
def vote_toggle(self, cr, uid, ids, user_ids=None, context=None):
- ''' Toggles voting '''
+ ''' Toggles voting. Done as SUPERUSER_ID because of write access on
+ mail.message not always granted. '''
if not user_ids:
user_ids = [uid]
for message in self.read(cr, uid, ids, ['vote_user_ids'], context=context):
for user_id in user_ids:
has_voted = user_id in message.get('vote_user_ids')
if not has_voted:
- self.write(cr, uid, message.get('id'), {'vote_user_ids': [(4, user_id)]}, context=context)
+ self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(4, user_id)]}, context=context)
else:
- self.write(cr, uid, message.get('id'), {'vote_user_ids': [(3, user_id)]}, context=context)
+ self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(3, user_id)]}, context=context)
return True
#------------------------------------------------------
@@ -171,17 +174,31 @@ class mail_message(osv.Model):
#------------------------------------------------------
def _message_dict_get(self, cr, uid, msg, context=None):
- """ Return a dict representation of the message browse record. """
+ """ Return a dict representation of the message browse record. A read
+ is performed to because of access rights issues (reading many2one
+ fields allow to have the foreign record name without having
+ to check external access rights).
+ """
has_voted = False
- vote_ids = self.pool.get('res.users').name_get(cr, uid, [user.id for user in msg.vote_user_ids], context=context)
+ vote_ids = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [user.id for user in msg.vote_user_ids], context=context)
for vote in vote_ids:
if vote[0] == uid:
has_voted = True
break
- attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context)]
- author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0]
- author_user_id = self.pool.get('res.users').name_get(cr, uid, [msg.author_id.user_ids[0].id], context=context)[0]
- partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context)
+ try:
+ attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context)]
+ except (orm.except_orm, osv.except_osv):
+ attachment_ids = []
+ try:
+ author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0]
+ is_author = uid in msg.author_id.user_ids
+ except (orm.except_orm, osv.except_osv):
+ author_id = False
+ is_author = False
+ try:
+ partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context)
+ except (orm.except_orm, osv.except_osv):
+ partner_ids = []
return {
'id': msg.id,
'type': msg.type,
@@ -193,7 +210,7 @@ class mail_message(osv.Model):
'subject': msg.subject,
'date': msg.date,
'author_id': author_id,
- 'author_user_id': author_user_id,
+ 'is_author': is_author,
'partner_ids': partner_ids,
'child_ids': [],
'vote_user_ids': vote_ids,
@@ -246,7 +263,7 @@ class mail_message(osv.Model):
limit = limit or self._message_read_limit
context = context or {}
if not ids:
- ids = self.search(cr, uid, domain, context=context, limit=limit)
+ ids = self.search(cr, SUPERUSER_ID, domain, context=context, limit=limit)
messages = self.browse(cr, uid, ids, context=context)
result = []
@@ -294,41 +311,99 @@ class mail_message(osv.Model):
cr.execute("""CREATE INDEX mail_message_model_res_id_idx ON mail_message (model, res_id)""")
def check_access_rule(self, cr, uid, ids, operation, context=None):
- """ mail.message access rule check
- - message received (a notification exists) -> ok
- - check rules of related document if exists
- - fallback on normal mail.message check """
+ """ Access rules of mail.message:
+ - read: if
+ - notification exist (I receive pushed message) OR
+ - author_id = pid (I am the author) OR
+ - I can read the related document if res_model, res_id
+ - Otherwise: raise
+ - create: if
+ - I am in the document message_follower_ids OR
+ - I can write on the related document if res_model, res_id
+ - Otherwise: raise
+ - write: if
+ - I can write on the related document if res_model, res_id
+ - Otherwise: raise
+ - unlink: if
+ - I can write on the related document if res_model, res_id
+ - Otherwise: raise
+ """
+ if uid == SUPERUSER_ID:
+ return
if isinstance(ids, (int, long)):
ids = [ids]
+ partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0]
- # check messages for which you have a notification
- partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
- not_obj = self.pool.get('mail.notification')
- not_ids = not_obj.search(cr, uid, [
- ('partner_id', '=', partner_id),
- ('message_id', 'in', ids),
- ], context=context)
- notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, uid, not_ids, context=context)
- if notification.message_id.id in ids]
-
- # check messages linked to an existing document
+ # Read mail_message.ids to have their values
model_record_ids = {}
- document_ids = []
- cr.execute('SELECT DISTINCT id, model, res_id FROM mail_message WHERE id = ANY (%s)', (ids,))
- for id, rmod, rid in cr.fetchall():
- if not (rmod and rid):
- continue
- document_ids.append(id)
- model_record_ids.setdefault(rmod, set()).add(rid)
+ message_values = dict.fromkeys(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, set()).add(rid)
+
+ # Read: Check for received notifications -> could become an ir.rule, but not till we do not have a many2one variable field
+ 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)]
+ else:
+ notified_ids = []
+ # Read: Check messages you are author -> could become an ir.rule, but not till we do not have a many2one variable field
+ if operation == 'read':
+ author_ids = [mid for mid, message in message_values.iteritems()
+ if message.get('author_id') and message.get('author_id') == partner_id]
+ else:
+ author_ids = []
+
+ # Create: Check message_follower_ids
+ if operation == 'create':
+ doc_follower_ids = []
+ for model, mids in model_record_ids.items():
+ fol_obj = self.pool.get('mail.followers')
+ fol_ids = fol_obj.search(cr, SUPERUSER_ID, [
+ ('res_model', '=', model),
+ ('res_id', 'in', list(mids)),
+ ('partner_id', '=', partner_id),
+ ], context=context)
+ fol_mids = [follower.res_id for follower in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)]
+ doc_follower_ids += [mid for mid, message in message_values.iteritems()
+ if message.get('res_model') == model and message.get('res_id') in fol_mids]
+ else:
+ doc_follower_ids = []
+
+ # Calculate remaining ids, and related model/res_ids
+ model_record_ids = {}
+ other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_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'])
+
+ # CRUD: Access rights related to the document
+ document_related_ids = []
for model, mids in model_record_ids.items():
model_obj = self.pool.get(model)
mids = model_obj.exists(cr, uid, mids)
- model_obj.check_access_rights(cr, uid, operation)
- model_obj.check_access_rule(cr, uid, mids, operation, context=context)
+ 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)
+ else:
+ 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]
- # fall back on classic operation for other ids
- other_ids = set(ids).difference(set(notified_ids), set(document_ids))
- super(mail_message, self).check_access_rule(cr, uid, other_ids, operation, context=None)
+ # Calculate remaining ids: if not void, raise an error
+ other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids), set(document_related_ids))
+ if not other_ids:
+ return
+ raise orm.except_orm(_('Access Denied'),
+ _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \
+ (self._description, operation))
def create(self, cr, uid, values, context=None):
if not values.get('message_id') and values.get('res_id') and values.get('model'):
@@ -337,6 +412,13 @@ class mail_message(osv.Model):
self.notify(cr, uid, newid, context=context)
return newid
+ def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
+ """ Override to explicitely call check_access_rule, that is not called
+ by the ORM. It instead directly fetches ir.rules and apply them. """
+ res = super(mail_message, self).read(cr, uid, ids, fields=fields, context=context, load=load)
+ self.check_access_rule(cr, uid, ids, 'read', context=context)
+ return res
+
def unlink(self, cr, uid, ids, context=None):
# cascade-delete attachments that are directly attached to the message (should only happen
# for mail.messages that act as parent for a standalone mail.mail record).
@@ -360,12 +442,14 @@ class mail_message(osv.Model):
partners_to_notify |= set(partner.id for partner in message.partner_ids)
# add all followers and set add them in partner_ids
if message.model and message.res_id:
- record = self.pool.get(message.model).browse(cr, uid, message.res_id, context=context)
+ record = self.pool.get(message.model).browse(cr, SUPERUSER_ID, message.res_id, context=context)
extra_notified = set(partner.id for partner in record.message_follower_ids)
missing_notified = extra_notified - partners_to_notify
if missing_notified:
- message.write({'partner_ids': [(4, p_id) for p_id in missing_notified]})
+ self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context)
partners_to_notify |= extra_notified
+ # # remove uid from partners
+ self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(3, uid)]}, context=context)
self.pool.get('mail.notification').notify(cr, uid, list(partners_to_notify), newid, context=context)
def copy(self, cr, uid, id, default=None, context=None):
diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml
index 914937a34f3..814702f6db4 100644
--- a/addons/mail/mail_message_view.xml
+++ b/addons/mail/mail_message_view.xml
@@ -95,7 +95,7 @@
- My Feeds
+ My Posts
mail.wall
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index abee20a35f8..c671dd55ec4 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -30,6 +30,7 @@ import xmlrpclib
from email.message import Message
from mail_message import decode
+from openerp import SUPERUSER_ID
from osv import osv, fields
from tools.safe_eval import safe_eval as eval
@@ -118,26 +119,27 @@ class mail_thread(osv.AbstractModel):
def _get_message_data(self, cr, uid, ids, name, args, context=None):
res = dict((id, dict(message_unread=False, message_summary='')) for id in ids)
- user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
+ partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
+ # search for unread messages, by reading directly mail.notification, as SUPERUSER
notif_obj = self.pool.get('mail.notification')
- notif_ids = notif_obj.search(cr, uid, [
+ notif_ids = notif_obj.search(cr, SUPERUSER_ID, [
('partner_id.user_ids', 'in', [uid]),
('message_id.res_id', 'in', ids),
('message_id.model', '=', self._name),
('read', '=', False)
], context=context)
- for notif in notif_obj.browse(cr, uid, notif_ids, context=context):
+ for notif in notif_obj.browse(cr, SUPERUSER_ID, notif_ids, context=context):
res[notif.message_id.res_id]['message_unread'] = True
- for thread in self.browse(cr, uid, ids, context=context):
- cls = res[thread.id]['message_unread'] and ' class="oe_kanban_mail_new"' or ''
- res[thread.id]['message_summary'] = "9 %d + %d" % (cls, len(thread.message_comment_ids), len(thread.message_follower_ids))
- res[thread.id]['message_is_follower'] = user.partner_id.id in [follower.id for follower in thread.message_follower_ids]
+ for thread in self.read(cr, uid, ids, ['message_follower_ids', 'message_comment_ids', 'message_ids'], context=context):
+ cls = res[thread['id']]['message_unread'] and ' class="oe_kanban_mail_new"' or ''
+ res[thread['id']]['message_summary'] = "9 %d + %d" % (cls, len(thread['message_comment_ids']), len(thread['message_follower_ids']))
+ res[thread['id']]['message_is_follower'] = partner_id in thread['message_follower_ids']
return res
def _search_unread(self, cr, uid, obj=None, name=None, domain=None, context=None):
- partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
+ partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
res = {}
notif_obj = self.pool.get('mail.notification')
notif_ids = notif_obj.search(cr, uid, [
@@ -196,6 +198,13 @@ class mail_thread(osv.AbstractModel):
fol_obj.unlink(cr, uid, fol_ids, context=context)
return super(mail_thread, self).unlink(cr, uid, ids, context=context)
+ def copy(self, cr, uid, id, default=None, context=None):
+ default = default or {}
+ default['message_ids'] = []
+ default['message_comment_ids'] = []
+ default['message_follower_ids'] = []
+ return super(mail_thread, self).copy(cr, uid, id, default=default, context=context)
+
#------------------------------------------------------
# mail.message wrappers and tools
#------------------------------------------------------
@@ -620,7 +629,7 @@ class mail_thread(osv.AbstractModel):
""" Wrapper on message_subscribe, using users. If user_ids is not
provided, subscribe uid instead. """
if not user_ids: user_ids = [uid]
- partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)]
+ partner_ids = [user['partner_id'][0] for user in self.pool.get('res.users').read(cr, uid, user_ids, ['partner_id'], context=context)]
return self.message_subscribe(cr, uid, ids, partner_ids, context=context)
def message_subscribe(self, cr, uid, ids, partner_ids, context=None):
@@ -631,7 +640,7 @@ class mail_thread(osv.AbstractModel):
""" Wrapper on message_subscribe, using users. If user_ids is not
provided, unsubscribe uid instead. """
if not user_ids: user_ids = [uid]
- partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)]
+ partner_ids = [user['partner_id'][0] for user in self.pool.get('res.users').read(cr, uid, user_ids, ['partner_id'], context=context)]
return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context)
def message_unsubscribe(self, cr, uid, ids, partner_ids, context=None):
diff --git a/addons/mail/res_partner_view.xml b/addons/mail/res_partner_view.xml
index 2a8430926d5..5c051fc89b3 100644
--- a/addons/mail/res_partner_view.xml
+++ b/addons/mail/res_partner_view.xml
@@ -9,6 +9,7 @@
+
diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv
index 2ec74086a34..26048e7a40c 100644
--- a/addons/mail/security/ir.model.access.csv
+++ b/addons/mail/security/ir.model.access.csv
@@ -1,13 +1,14 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_mail_global,mail.mail,model_mail_mail,base.group_system,1,1,1,1
-access_mail_message_all,mail.message.all,model_mail_message,,1,0,0,0
+access_mail_message_all,mail.message.all,model_mail_message,,1,0,1,0
access_mail_message_group_user,mail.message.group.user,model_mail_message,base.group_user,1,1,1,1
-access_mail_thread,mail.thread,model_mail_thread,base.group_user,1,1,1,0
-access_mail_followers_all,mail.followers.all,model_mail_followers,,1,1,1,1
-access_mail_notification_all,mail.notification.all,model_mail_notification,,1,1,1,1
-access_mail_group,mail.group,model_mail_group,base.group_user,1,1,1,1
+access_mail_mail_all,mail.mail.all,model_mail_mail,,0,0,1,0
+access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,1,1,1,1
+access_mail_followers_all,mail.followers.all,model_mail_followers,,0,0,0,0
+access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1
+access_mail_notification_all,mail.notification.all,model_mail_notification,,1,0,0,0
+access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1
+access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0
+access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1
+access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0
access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0
-access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,1
-access_mail_mail_user,mail.mail,model_mail_mail,base.group_user,1,1,1,0
-access_mail_mail_manager,mail.mail,model_mail_mail,group_mail_manager,1,1,1,1
access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,1
diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml
index 1d6d8d90579..b503565bd11 100644
--- a/addons/mail/security/mail_security.xml
+++ b/addons/mail/security/mail_security.xml
@@ -2,20 +2,6 @@
-
-
- Home
-
- 26
-
-
-
-
- Mail manager
-
-
-
-
Mail.group: access only public and joined groups
@@ -24,5 +10,18 @@
['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.id]), '&', ('public','=','groups'), ('group_public_id','in', [x.id for x in user.groups_id])]
+
+
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css
index 717d0439486..e69eaadbcdb 100644
--- a/addons/mail/static/src/css/mail.css
+++ b/addons/mail/static/src/css/mail.css
@@ -124,6 +124,14 @@
}
+/* ------------------------------------------------------------ */
+/* Followers
+/* ------------------------------------------------------------ */
+
+.openerp div.oe_mail_recthread_aside h4 {
+ display: inline-block;
+}
+
/* ------------------------------------------------------------ */
/* Thread
/* ------------------------------------------------------------ */
@@ -224,7 +232,7 @@
clear: both;
}
-.openerp .oe_mail_msg_content a {
+.openerp .oe_chatter a {
cursor: pointer;
}
@@ -258,30 +266,6 @@
display: none;
}
-/*--------------------------------------------------------------*/
-/* mail.vote
-/*--------------------------------------------------------------*/
-
-.openerp .oe_mail_msg_content button.oe_mail_msg_vote {
- height:21px;
- width: 30px;
- padding: 1px;
- background: #8A89BA;
- margin-top: -4px;
-}
-
-.openerp .oe_mail_msg_content button.oe_mail_msg_vote_true {
- background:#DC5F59;
-}
-
-.openerp .oe_mail_msg_content button.oe_mail_msg_vote span {
- color: white;
-}
-
-.openerp .oe_mail_msg_content span.oe_mail_vote_count{
- color: #807FB4;
-}
-
/* ------------------------------------------------------------ */
/* mail.compose.message form view & OpenERP hacks
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index 326b2f442b1..196c54c8296 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -56,11 +56,6 @@ openerp.mail = function(session) {
return session.origin + '/web/binary/saveas?session_id=' + session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id'];
},
- /** Check if the current user is the message author */
- is_author: function (widget, message_user_id) {
- return (widget.session && widget.session.uid != 0 && widget.session.uid == message_user_id);
- },
-
/** Replaces some expressions
* - :name - shortcut to an image
*/
@@ -301,6 +296,7 @@ openerp.mail = function(session) {
// TDE TODO: check for deferred, not sure it is correct
this._super.apply(this, arguments);
this.bind_events();
+ this.display_user_avatar();
// fetch and display message, using message_ids if set
var display_done = $.when(this.message_fetch(true, [], {})).then(this.proxy('do_customize_display'));
// add message composition form view
@@ -313,7 +309,6 @@ openerp.mail = function(session) {
/** Customize the display
* - show_header_compose: show the composition form in the header */
do_customize_display: function() {
- this.display_user_avatar();
if (this.options.show_header_compose) {
this.$el.find('div.oe_mail_thread_action').eq(0).show();
}
@@ -491,8 +486,7 @@ openerp.mail = function(session) {
* - record.date: formatting according to the user timezone
* - record.timerelative: relative time givein by timeago lib
* - record.avatar: image url
- * - record.attachment_ids[].url: url of each attachment
- * - record.is_author: is the current user the author of the record */
+ * - record.attachment_ids[].url: url of each attachment */
display_record: function (record) {
// formatting and additional fields
record.date = session.web.format_value(record.date, {type:"datetime"});
@@ -506,7 +500,6 @@ openerp.mail = function(session) {
var attach = record.attachment_ids[l];
attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach);
}
- record.is_author = mail.ChatterUtils.is_author(this, record.author_user_id[0]);
// add to internal storage
this.records[record.id] = record;
// render, add the expand feature
@@ -649,12 +642,15 @@ openerp.mail = function(session) {
// update domain
var domain = this.options.domain.concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]);
// create and render Thread widget
+ var show_header_compose = this.view.is_action_enabled('edit') ||
+ (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
this.$el.find('div.oe_mail_recthread_main').empty();
var thread = new mail.Thread(self, domain, this.options.context,
{ 'thread_level': this.options.thread_level,
- 'use_composer': true,
+ 'show_header_compose': show_header_compose,
+ 'use_composer': show_header_compose,
'show_dd_delete': true,
- 'show_reply_by_email': true });
+ 'show_reply_by_email': show_header_compose });
return thread.appendTo(this.$el.find('div.oe_mail_recthread_main'));
},
});
diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js
index d1dd9f89fb7..743c4704330 100644
--- a/addons/mail/static/src/js/mail_followers.js
+++ b/addons/mail/static/src/js/mail_followers.js
@@ -45,8 +45,8 @@ openerp_mail_followers = function(session, mail) {
},
reinit: function() {
- this.$el.find('button.oe_mail_button_follow').hide();
- this.$el.find('button.oe_mail_button_unfollow').hide();
+ this.message_is_follower == undefined;
+ this.display_buttons();
},
bind_events: function() {
@@ -55,7 +55,7 @@ openerp_mail_followers = function(session, mail) {
.mouseover(function () { $(this).html('Unfollow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); })
.mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); });
this.$el.on('click', 'button.oe_mail_button_follow', function () { self.do_follow(); });
- this.$el.on('click', 'button.oe_mail_button_invite', function(event) {
+ this.$el.on('click', 'a.oe_mail_invite', function(event) {
action = {
type: 'ir.actions.act_window',
res_model: 'mail.wizard.invite',
@@ -74,41 +74,65 @@ openerp_mail_followers = function(session, mail) {
read_value: function() {
var self = this;
- return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).pipe(function (results) {
- return results[0].message_follower_ids;
- }).pipe(this.proxy('set_value'));
+ return this.ds_model.read_ids([this.view.datarecord.id], ['message_is_follower', 'message_follower_ids']).then(function (results) {
+ self.set_value(results[0].message_follower_ids, results[0].message_is_follower);
+ });
},
- set_value: function(value_) {
+ set_value: function(value_, message_is_follower) {
this.reinit();
if (! this.view.datarecord.id ||
session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) {
- this.$el.find('div.oe_mail_recthread_aside').hide();
+ this.$('div.oe_mail_recthread_aside').hide();
return;
}
- return this.fetch_followers(value_ || this.get_value());
+ return this.fetch_followers(value_ || this.get_value(), message_is_follower);
},
- fetch_followers: function (value_) {
- return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers'));
+ fetch_followers: function (value_, message_is_follower) {
+ this.value = value_;
+ this.message_is_follower = message_is_follower || (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
+ return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers'), this.proxy('display_generic'));
+ },
+
+
+ /* Display generic info about follower, for people not having access to res_partner */
+ display_generic: function (error, event) {
+ event.preventDefault();
+ var node_user_list = this.$('ul.oe_mail_followers_display').empty();
+ // format content: Followers (You and 0 other) // Followers (3)
+ var content = this.options.title;
+ if (this.message_is_follower) {
+ content += ' (You and ' + (this.value.length-1) + ' other)';
+ }
+ else {
+ content += ' (' + this.value.length + ')'
+ }
+ this.$('div.oe_mail_recthread_followers h4').html(content);
+ this.display_buttons();
+ return $.when();
},
/** Display the followers, evaluate is_follower directly */
display_followers: function (records) {
var self = this;
- this.message_is_follower = _.indexOf(_.flatten(_.pluck(records, 'user_ids')), this.session.uid) != -1;
- var node_user_list = this.$el.find('ul.oe_mail_followers_display').empty();
- this.$el.find('div.oe_mail_recthread_followers h4').html(this.options.title + ' (' + records.length + ')');
+ var node_user_list = this.$('ul.oe_mail_followers_display').empty();
+ this.$('div.oe_mail_recthread_followers h4').html(this.options.title + ' (' + records.length + ')');
_(records).each(function (record) {
record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id);
$(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list);
});
- if (this.message_is_follower) {
- this.$el.find('button.oe_mail_button_follow').hide();
- this.$el.find('button.oe_mail_button_unfollow').show(); }
- else {
- this.$el.find('button.oe_mail_button_follow').show();
- this.$el.find('button.oe_mail_button_unfollow').hide(); }
+ this.display_buttons();
+ },
+
+ display_buttons: function () {
+ this.$('button.oe_mail_button_follow').hide();
+ this.$('button.oe_mail_button_unfollow').hide();
+ this.$('span.oe_mail_invite_wrapper').hide();
+ if (! this.view.is_action_enabled('edit')) return;
+ this.$('span.oe_mail_invite_wrapper').show();
+ if (this.message_is_follower) { this.$('button.oe_mail_button_unfollow').show(); }
+ else if (this.message_is_follower == false) { this.$('button.oe_mail_button_follow').show(); }
},
do_follow: function () {
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
index e3586e723e4..c54bd4dbb2d 100644
--- a/addons/mail/static/src/xml/mail.xml
+++ b/addons/mail/static/src/xml/mail.xml
@@ -140,7 +140,7 @@
-
+
Reply
@@ -185,7 +185,7 @@
votes
-