[FIX] mail: fixed wrong var name in notify; fixed a missing email in tests.
[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 from openerp.osv import osv, fields
22 from openerp import tools, SUPERUSER_ID
23 from openerp.tools.translate import _
24 from openerp.tools.mail import plaintext2html
25
26 class mail_followers(osv.Model):
27     """ mail_followers holds the data related to the follow mechanism inside
28         OpenERP. Partners can choose to follow documents (records) of any kind
29         that inherits from mail.thread. Following documents allow to receive
30         notifications for new messages.
31         A subscription is characterized by:
32             :param: res_model: model of the followed objects
33             :param: res_id: ID of resource (may be 0 for every objects)
34     """
35     _name = 'mail.followers'
36     _rec_name = 'partner_id'
37     _log_access = False
38     _description = 'Document Followers'
39     _columns = {
40         'res_model': fields.char('Related Document Model', size=128,
41                         required=True, select=1,
42                         help='Model of the followed resource'),
43         'res_id': fields.integer('Related Document ID', select=1,
44                         help='Id of the followed resource'),
45         'partner_id': fields.many2one('res.partner', string='Related Partner',
46                         ondelete='cascade', required=True, select=1),
47         'subtype_ids': fields.many2many('mail.message.subtype', string='Subtype',
48             help="Message subtypes followed, meaning subtypes that will be pushed onto the user's Wall."),
49     }
50
51
52 class mail_notification(osv.Model):
53     """ Class holding notifications pushed to partners. Followers and partners
54         added in 'contacts to notify' receive notifications. """
55     _name = 'mail.notification'
56     _rec_name = 'partner_id'
57     _log_access = False
58     _description = 'Notifications'
59
60     _columns = {
61         'partner_id': fields.many2one('res.partner', string='Contact',
62                         ondelete='cascade', required=True, select=1),
63         'read': fields.boolean('Read', select=1),
64         'starred': fields.boolean('Starred', select=1,
65             help='Starred message that goes into the todo mailbox'),
66         'message_id': fields.many2one('mail.message', string='Message',
67                         ondelete='cascade', required=True, select=1),
68     }
69
70     _defaults = {
71         'read': False,
72         'starred': False,
73     }
74
75     def init(self, cr):
76         cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('mail_notification_partner_id_read_starred_message_id',))
77         if not cr.fetchone():
78             cr.execute('CREATE INDEX mail_notification_partner_id_read_starred_message_id ON mail_notification (partner_id, read, starred, message_id)')
79
80     def get_partners_to_notify(self, cr, uid, message, partners_to_notify=None, context=None):
81         """ Return the list of partners to notify, based on their preferences.
82
83             :param browse_record message: mail.message to notify
84             :param list partners_to_notify: optional list of partner ids restricting
85                 the notifications to process
86         """
87         notify_pids = []
88         for notification in message.notification_ids:
89             if notification.read:
90                 continue
91             partner = notification.partner_id
92             # If partners_to_notify specified: restrict to them
93             if partners_to_notify and partner.id not in partners_to_notify:
94                 continue
95             # Do not send to partners without email address defined
96             if not partner.email:
97                 continue
98             # Partner does not want to receive any emails or is opt-out
99             if partner.notification_email_send == 'none':
100                 continue
101             # Partner wants to receive only emails and comments
102             if partner.notification_email_send == 'comment' and message.type not in ('email', 'comment'):
103                 continue
104             # Partner wants to receive only emails
105             if partner.notification_email_send == 'email' and message.type != 'email':
106                 continue
107             notify_pids.append(partner.id)
108         return notify_pids
109
110     def get_signature_footer(self, cr, uid, user_id, res_model=None, res_id=None, context=None):
111         """ Format a standard footer for notification emails (such as pushed messages
112             notification or invite emails).
113             Format:
114                 <p>--<br />
115                     Administrator
116                 </p>
117                 <div>
118                     <small>Send by <a ...>Your Company</a> using <a ...>OpenERP</a>.</small> OR
119                     <small>Send by Administrator using <a ...>OpenERP</a>.</small>
120                 </div>
121         """
122         footer = ""
123         if not user_id:
124             return footer
125
126         # add user signature
127         user = self.pool.get("res.users").browse(cr, SUPERUSER_ID, [user_id], context=context)[0]
128         if user.signature:
129             signature = plaintext2html(user.signature)
130         else:
131             signature = "--<br />%s" % user.name
132         footer = tools.append_content_to_html(footer, signature, plaintext=False, container_tag='p')
133
134         # add company signature
135         if user.company_id:
136             company = user.company_id.website and "<a style='color:inherit' href='%s'>%s</a>" % (user.company_id.website, user.company_id.name) or user.company_id.name
137         else:
138             company = user.name
139         signature_company = _('<small>Send by %(company)s using %(openerp)s.</small>' % {
140                 'company': company,
141                 'openerp': "<a style='color:inherit' href='https://www.openerp.com/'>OpenERP</a>"
142             })
143         footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div')
144
145         return footer
146
147     def _notify(self, cr, uid, msg_id, partners_to_notify=None, context=None):
148         """ Send by email the notification depending on the user preferences
149
150             :param list partners_to_notify: optional list of partner ids restricting
151                 the notifications to process
152         """
153         if context is None:
154             context = {}
155         mail_message_obj = self.pool.get('mail.message')
156
157         # optional list of partners to notify: subscribe them if not already done or update the notification
158         if partners_to_notify:
159             notifications_to_update = []
160             notified_partners = []
161             notif_ids = self.search(cr, SUPERUSER_ID, [('message_id', '=', msg_id), ('partner_id', 'in', partners_to_notify)], context=context)
162             for notification in self.browse(cr, SUPERUSER_ID, notif_ids, context=context):
163                 notified_partners.append(notification.partner_id.id)
164                 notifications_to_update.append(notification.id)
165             partners_to_notify = filter(lambda item: item not in notified_partners, partners_to_notify)
166             if notifications_to_update:
167                 self.write(cr, SUPERUSER_ID, notifications_to_update, {'read': False}, context=context)
168             mail_message_obj.write(cr, uid, msg_id, {'notified_partner_ids': [(4, id) for id in partners_to_notify]}, context=context)
169
170         # mail_notify_noemail (do not send email) or no partner_ids: do not send, return
171         if context.get('mail_notify_noemail'):
172             return True
173         # browse as SUPERUSER_ID because of access to res_partner not necessarily allowed
174         msg = self.pool.get('mail.message').browse(cr, SUPERUSER_ID, msg_id, context=context)
175         notify_partner_ids = self.get_partners_to_notify(cr, uid, msg, partners_to_notify=partners_to_notify, context=context)
176         if not notify_partner_ids:
177             return True
178
179         # add the context in the email
180         # TDE FIXME: commented, to be improved in a future branch
181         # quote_context = self.pool.get('mail.message').message_quote_context(cr, uid, msg_id, context=context)
182
183         # add signature
184         body_html = msg.body
185         user_id = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0] and msg.author_id.user_ids[0].id or None
186         signature_company = self.get_signature_footer(cr, uid, user_id, res_model=msg.model, res_id=msg.res_id, context=context)
187         body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div')
188
189         mail_values = {
190             'mail_message_id': msg.id,
191             'auto_delete': True,
192             'body_html': body_html,
193             'recipient_ids': [(4, id) for id in notify_partner_ids]
194         }
195         if msg.email_from:
196             mail_values['email_from'] = msg.email_from
197         if msg.reply_to:
198             mail_values['reply_to'] = msg.reply_to
199         mail_mail = self.pool.get('mail.mail')
200         email_notif_id = mail_mail.create(cr, uid, mail_values, context=context)
201         try:
202             return mail_mail.send(cr, uid, [email_notif_id], context=context)
203         except Exception:
204             return False