[IMP] better demo data
[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 openerp import SUPERUSER_ID
23 from osv import osv
24 from osv import fields
25 import tools
26
27
28 class mail_followers(osv.Model):
29     """ mail_followers holds the data related to the follow mechanism inside
30         OpenERP. Partners can choose to follow documents (records) of any kind
31         that inherits from mail.thread. Following documents allow to receive
32         notifications for new messages.
33         A subscription is characterized by:
34             :param: res_model: model of the followed objects
35             :param: res_id: ID of resource (may be 0 for every objects)
36     """
37     _name = 'mail.followers'
38     _rec_name = 'partner_id'
39     _log_access = False
40     _description = 'Document Followers'
41     _columns = {
42         'res_model': fields.char('Related Document Model', size=128,
43                         required=True, select=1,
44                         help='Model of the followed resource'),
45         'res_id': fields.integer('Related Document ID', select=1,
46                         help='Id of the followed resource'),
47         'partner_id': fields.many2one('res.partner', string='Related Partner',
48                         ondelete='cascade', required=True, select=1),
49         'subtype_ids': fields.many2many('mail.message.subtype', string='Subtype',
50             help="Message subtypes followed, meaning subtypes that will be pushed onto the user's Wall."),
51     }
52
53
54 class mail_notification(osv.Model):
55     """ Class holding notifications pushed to partners. Followers and partners
56         added in 'contacts to notify' receive notifications. """
57     _name = 'mail.notification'
58     _rec_name = 'partner_id'
59     _log_access = False
60     _description = 'Notifications'
61
62     _columns = {
63         'partner_id': fields.many2one('res.partner', string='Contact',
64                         ondelete='cascade', required=True, select=1),
65         'read': fields.boolean('Read', select=1),
66         'message_id': fields.many2one('mail.message', string='Message',
67                         ondelete='cascade', required=True, select=1),
68     }
69
70     _defaults = {
71         'read': False,
72     }
73
74     def init(self, cr):
75         cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('mail_notification_partner_id_read_message_id',))
76         if not cr.fetchone():
77             cr.execute('CREATE INDEX mail_notification_partner_id_read_message_id ON mail_notification (partner_id, read, message_id)')
78
79     def create(self, cr, uid, vals, context=None):
80         """ Override of create to check that we can not create a notification
81             for a message the user can not read. """
82         if self.pool.get('mail.message').check_access_rights(cr, uid, 'read'):
83             return super(mail_notification, self).create(cr, uid, vals, context=context)
84         return False
85
86     def set_message_read(self, cr, uid, msg_ids, read=None, context=None):
87         """ Set messages as (un)read. Technically, the notifications related
88             to uid are set to (un)read. If for some msg_ids there are missing
89             notifications (i.e. due to load more or thread parent fetching),
90             they are created.
91
92             :param bool read: (un)read notification
93         """
94         user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
95         notif_ids = self.search(cr, uid, [
96             ('partner_id', '=', user_pid),
97             ('message_id', 'in', msg_ids)
98             ], context=context)
99
100         # all message have notifications: already set them as (un)read
101         if len(notif_ids) == len(msg_ids):
102             return self.write(cr, uid, notif_ids, {'read': read}, context=context)
103
104         # some messages do not have notifications: find which one, create notification, update read status
105         notified_msg_ids = [notification.message_id.id for notification in self.browse(cr, uid, notif_ids, context=context)]
106         to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids))
107         for msg_id in to_create_msg_ids:
108             self.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context)
109         return self.write(cr, uid, notif_ids, {'read': read}, context=context)
110
111     def get_partners_to_notify(self, cr, uid, message, context=None):
112         """ Return the list of partners to notify, based on their preferences.
113
114             :param browse_record message: mail.message to notify
115         """
116         notify_pids = []
117         for notification in message.notification_ids:
118             if notification.read:
119                 continue
120             partner = notification.partner_id
121             # Do not send an email to the writer
122             if partner.user_ids and partner.user_ids[0].id == uid:
123                 continue
124             # Do not send to partners without email address defined
125             if not partner.email:
126                 continue
127             # Partner does not want to receive any emails
128             if partner.notification_email_send == 'none':
129                 continue
130             # Partner wants to receive only emails and comments
131             if partner.notification_email_send == 'comment' and message.type not in ('email', 'comment'):
132                 continue
133             # Partner wants to receive only emails
134             if partner.notification_email_send == 'email' and message.type != 'email':
135                 continue
136             notify_pids.append(partner.id)
137         return notify_pids
138
139     def _notify(self, cr, uid, msg_id, context=None):
140         """ Send by email the notification depending on the user preferences """
141         if context is None:
142             context = {}
143         # mail_noemail (do not send email) or no partner_ids: do not send, return
144         if context.get('mail_noemail'):
145             return True
146         msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context)
147
148         notify_partner_ids = self.get_partners_to_notify(cr, uid, msg, context=context)
149         if not notify_partner_ids:
150             return True
151
152         # add the context in the email
153         # TDE FIXME: commented, to be improved in a future branch
154         # quote_context = self.pool.get('mail.message').message_quote_context(cr, uid, msg_id, context=context)
155
156         mail_mail = self.pool.get('mail.mail')
157         # add signature
158         body_html = msg.body
159         # if quote_context:
160             # body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
161         signature = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0].signature or ''
162         if signature:
163             body_html = tools.append_content_to_html(body_html, signature, plaintext=True, container_tag='div')
164
165         mail_values = {
166             'mail_message_id': msg.id,
167             'email_to': [],
168             'auto_delete': True,
169             'body_html': body_html,
170             'state': 'outgoing',
171         }
172         mail_values['email_to'] = ', '.join(mail_values['email_to'])
173         email_notif_id = mail_mail.create(cr, uid, mail_values, context=context)
174         return mail_mail.send(cr, uid, [email_notif_id], recipient_ids=notify_partner_ids, context=context)