[MERGE]merge with trunk addons
[odoo/odoo.git] / addons / mail / mail_followers.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2009-today OpenERP SA (<http://www.openerp.com>)
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>
19 #
20 ##############################################################################
21
22 from osv import osv
23 from osv import fields
24 import tools
25
26
27 class mail_followers(osv.Model):
28     """ mail_followers holds the data related to the follow mechanism inside
29         OpenERP. Partners can choose to follow documents (records) of any kind
30         that inherits from mail.thread. Following documents allow to receive
31         notifications for new messages.
32         A subscription is characterized by:
33             :param: res_model: model of the followed objects
34             :param: res_id: ID of resource (may be 0 for every objects)
35     """
36     _name = 'mail.followers'
37     _rec_name = 'partner_id'
38     _log_access = False
39     _description = 'Document Followers'
40     _columns = {
41         'res_model': fields.char('Related Document Model', size=128,
42                         required=True, select=1,
43                         help='Model of the followed resource'),
44         'res_id': fields.integer('Related Document ID', select=1,
45                         help='Id of the followed resource'),
46         'partner_id': fields.many2one('res.partner', string='Related Partner',
47                         ondelete='cascade', required=True, select=1),
48         'subtype_ids': fields.many2many('mail.message.subtype',
49                                         'mail_message_subtyp_rel',
50                                         'subscription_id', 'subtype_id', 'Subtype',
51                                         help = "linking some subscription to several subtype for projet/task"),
52     }
53
54
55 class mail_notification(osv.Model):
56     """ Class holding notifications pushed to partners. Followers and partners
57         added in 'contacts to notify' receive notifications. """
58     _name = 'mail.notification'
59     _rec_name = 'partner_id'
60     _log_access = False
61     _description = 'Notifications'
62
63     _columns = {
64         'partner_id': fields.many2one('res.partner', string='Contact',
65                         ondelete='cascade', required=True),
66         'read': fields.boolean('Read'),
67         'message_id': fields.many2one('mail.message', string='Message',
68                         ondelete='cascade', required=True),
69     }
70
71     _defaults = {
72         'read': False,
73     }
74
75     def init(self, cr):
76         cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('mail_notification_partner_id_read_message_id',))
77         if not cr.fetchone():
78             cr.execute('CREATE INDEX mail_notification_partner_id_read_message_id ON mail_notification (partner_id, read, message_id)')
79
80     def create(self, cr, uid, vals, context=None):
81         """ Override of create to check that we can not create a notification
82             for a message the user can not read. """
83         if self.pool.get('mail.message').check_access_rights(cr, uid, 'read'):
84             return super(mail_notification, self).create(cr, uid, vals, context=context)
85         return False
86
87     def set_message_read(self, cr, uid, msg_id, context=None):
88         partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
89         notif_ids = self.search(cr, uid, [('partner_id', '=', partner_id), ('message_id', '=', msg_id)], context=context)
90         return self.write(cr, uid, notif_ids, {'read': True}, context=context)
91
92     def get_partners_to_notify(self, cr, uid, partner_ids, message, context=None):
93         """ Return the list of partners to notify, based on their preferences.
94
95             :param browse_record message: mail.message to notify
96         """
97         notify_pids = []
98         for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context):
99             # Do not send an email to the writer
100             if partner.user_ids and partner.user_ids[0].id == uid:
101                 continue
102             # Do not send to partners without email address defined
103             if not partner.email:
104                 continue
105             # Partner does not want to receive any emails
106             if partner.notification_email_send == 'none':
107                 continue
108             # Partner wants to receive only emails and comments
109             if partner.notification_email_send == 'comment' and message.type not in ('email', 'comment'):
110                 continue
111             # Partner wants to receive only emails
112             if partner.notification_email_send == 'email' and message.type != 'email':
113                 continue
114             notify_pids.append(partner.id)
115         return notify_pids
116
117     def notify(self, cr, uid, partner_ids, msg_id, context=None):
118         """ Send by email the notification depending on the user preferences """
119         context = context or {}
120         # mail_noemail (do not send email) or no partner_ids: do not send, return
121         if context.get('mail_noemail') or not partner_ids:
122             return True
123         msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context)
124
125         notify_partner_ids = self.get_partners_to_notify(cr, uid, partner_ids, msg, context=context)
126         if not notify_partner_ids:
127             return True
128
129         mail_mail = self.pool.get('mail.mail')
130         # add signature
131         body_html = msg.body
132         signature = msg.author_id and msg.author_id.user_ids[0].signature or ''
133         if signature:
134             body_html = tools.append_content_to_html(body_html, signature)
135
136         mail_values = {
137             'mail_message_id': msg.id,
138             'email_to': [],
139             'auto_delete': True,
140             'body_html': body_html,
141             'state': 'outgoing',
142         }
143         mail_values['email_to'] = ', '.join(mail_values['email_to'])
144         email_notif_id = mail_mail.create(cr, uid, mail_values, context=context)
145         return mail_mail.send(cr, uid, [email_notif_id], recipient_ids=notify_partner_ids, context=context)