diff options
| author | Rajesh Prajapati (OpenERP) <rpr@tinyerp.com> | 2012-10-05 17:35:03 +0530 |
|---|---|---|
| committer | Rajesh Prajapati (OpenERP) <rpr@tinyerp.com> | 2012-10-05 17:35:03 +0530 |
| commit | cdff4611b0a588546afb9b706bbd2d0fbda7bf2f (patch) | |
| tree | 0a0a99b33e52547987ab69b2a29f3ec23c188142 /addons/mail/mail_thread.py | |
| parent | 7202b8f7efbc76e2a40b1a4a8d7a95ed0d2ce573 (diff) | |
| parent | ba97319054728490e4d8a601382dd6fd2ab4f970 (diff) | |
[MERGE] merge with main addons
bzr revid: rpr@tinyerp.com-20121005120503-07e0zo8ucv8k0q3s
Diffstat (limited to 'addons/mail/mail_thread.py')
| -rw-r--r-- | addons/mail/mail_thread.py | 143 |
1 files changed, 121 insertions, 22 deletions
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index abee20a35f8..9f53b4c08b1 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 @@ -95,6 +96,7 @@ class many2many_reference(fields.many2many): 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 act as a discussion topic on which messages can be attached. Public @@ -115,29 +117,64 @@ class mail_thread(osv.AbstractModel): ''' _name = 'mail.thread' _description = 'Email Thread' + _mail_autothread = True def _get_message_data(self, cr, uid, ids, name, args, context=None): + """ Computes: + - message_unread: has uid unread message for the document + - message_summary: html snippet summarizing the Chatter for kanban views """ 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) + # 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'] = "<span%s><span class='oe_e'>9</span> %d</span> <span><span class='oe_e'>+</span> %d</span>" % (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] + + return res + + def _get_subscription_data(self, cr, uid, ids, name, args, context=None): + """ Computes: + - message_is_follower: is uid in the document followers + - message_subtype_data: data about document subtypes: which are + available, which are followed if any """ + res = dict((id, dict(message_subtype_data='', message_is_follower=False)) for id in ids) + user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + + # find current model subtypes, add them to a dictionary + subtype_obj = self.pool.get('mail.message.subtype') + subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) + subtype_dict = dict((subtype.name, dict(default=subtype.default, followed=False, id=subtype.id)) for subtype in subtype_obj.browse(cr, uid, subtype_ids, context=context)) + for id in ids: + res[id]['message_subtype_data'] = subtype_dict.copy() + + # find the document followers, update the data + fol_obj = self.pool.get('mail.followers') + fol_ids = fol_obj.search(cr, uid, [ + ('partner_id', '=', user_pid), + ('res_id', 'in', ids), + ('res_model', '=', self._name), + ], context=context) + for fol in fol_obj.browse(cr, uid, fol_ids, context=context): + thread_subtype_dict = res[fol.res_id]['message_subtype_data'] + res[fol.res_id]['message_is_follower'] = True + for subtype in fol.subtype_ids: + thread_subtype_dict[subtype.name]['followed'] = True + res[fol.res_id]['message_subtype_data'] = thread_subtype_dict + 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, [ @@ -150,8 +187,13 @@ class mail_thread(osv.AbstractModel): return [('id', 'in', res.keys())] _columns = { - 'message_is_follower': fields.function(_get_message_data, - type='boolean', string='Is a Follower', multi='_get_message_data'), + 'message_is_follower': fields.function(_get_subscription_data, + type='boolean', string='Is a Follower', multi='_get_subscription_data,'), + 'message_subtype_data': fields.function(_get_subscription_data, + type='text', string='Subscription data', multi="_get_subscription_data", + 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'), @@ -196,6 +238,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 #------------------------------------------------------ @@ -562,12 +611,12 @@ class mail_thread(osv.AbstractModel): "now deprecated res.log.") self.message_post(cr, uid, [id], message, context=context) - def message_post(self, cr, uid, thread_id, body='', subject=False, - type='notification', parent_id=False, attachments=None, context=None, **kwargs): + def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification', + subtype=None, parent_id=False, attachments=None, context=None, **kwargs): """ Post a new message in an existing thread, returning the new mail.message ID. Extra keyword arguments will be used as default column values for the new mail.message record. - + Auto link messages for same id and object :param int thread_id: thread ID to post into, or list with one ID :param str body: body of the message, usually raw HTML that will be sanitized @@ -578,10 +627,11 @@ class mail_thread(osv.AbstractModel): ``(name,content)``, where content is NOT base64 encoded :return: ID of newly created mail.message """ + context = context or {} attachments = attachments or [] - assert (not thread_id) or isinstance(thread_id, (int,long)) or \ - (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id" + assert (not thread_id) or isinstance(thread_id, (int, long)) or \ + (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id" if isinstance(thread_id, (list, tuple)): thread_id = thread_id and thread_id[0] @@ -599,38 +649,85 @@ class mail_thread(osv.AbstractModel): } attachment_ids.append((0, 0, data_attach)) + # get subtype + if not subtype: + subtype = 'mail.mt_comment' + s = subtype.split('.') + if len(s)==1: + s = ('mail', s[0]) + ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, s[0], s[1]) + subtype_id = ref and ref[1] or False + + model = context.get('thread_model', self._name) if thread_id else False + messages = self.pool.get('mail.message') + + #auto link messages for same id and object + if self._mail_autothread and thread_id: + message_ids = messages.search(cr, uid, ['&',('res_id', '=', thread_id),('model','=',model)], context=context) + if len(message_ids): + parent_id = min(message_ids) + + values = kwargs values.update({ - 'model': context.get('thread_model', self._name) if thread_id else False, + 'model': model, 'res_id': thread_id or False, 'body': body, - 'subject': subject, + 'subject': subject or False, 'type': type, 'parent_id': parent_id, 'attachment_ids': attachment_ids, + 'subtype_id': subtype_id, }) - for x in ('from', 'to', 'cc'): values.pop(x, None) # Avoid warnings - return self.pool.get('mail.message').create(cr, uid, values, context=context) + # Avoid warnings about non-existing fields + for x in ('from', 'to', 'cc'): + values.pop(x, None) + + return messages.create(cr, uid, values, context=context) #------------------------------------------------------ # Followers API #------------------------------------------------------ - def message_subscribe_users(self, cr, uid, ids, user_ids=None, context=None): + def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification', + subtype=None, parent_id=False, attachments=None, context=None, **kwargs): + added_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type, + subtype=subtype, parent_id=parent_id, attachments=attachments, context=context) + added_message = self.pool.get('mail.message').message_read(cr, uid, [added_message_id]) + + return added_message + + def get_message_subtypes(self, cr, uid, ids, context=None): + """ message_subtype_data: data about document subtypes: which are + available, which are followed if any """ + return self._get_subscription_data(cr, uid, ids, None, None, context=context) + + def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, subscribe uid instead. """ - if not user_ids: user_ids = [uid] + if not user_ids: + return False partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)] - return self.message_subscribe(cr, uid, ids, partner_ids, context=context) + return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, context=context) - def message_subscribe(self, cr, uid, ids, partner_ids, context=None): + def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None): """ Add partners to the records followers. """ - return self.write(cr, uid, ids, {'message_follower_ids': [(4, pid) for pid in partner_ids]}, context=context) + self.write(cr, uid, ids, {'message_follower_ids': [(4, pid) for pid in partner_ids]}, context=context) + # if subtypes are not specified (and not set to a void list), fetch default ones + if subtype_ids is None: + subtype_obj = self.pool.get('mail.message.subtype') + subtype_ids = subtype_obj.search(cr, uid, [('default', '=', True), '|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) + # update the subscriptions + fol_obj = self.pool.get('mail.followers') + fol_ids = fol_obj.search(cr, 1, [('res_model', '=', self._name), ('res_id', 'in', ids), ('partner_id', 'in', partner_ids)], context=context) + fol_obj.write(cr, 1, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) + return True def message_unsubscribe_users(self, cr, uid, ids, user_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, unsubscribe uid instead. """ - if not user_ids: user_ids = [uid] + 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)] return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context) @@ -665,3 +762,5 @@ class mail_thread(osv.AbstractModel): partner_id = %s ''', (ids, self._name, partner_id)) return True + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
