diff --git a/addons/mail/models/mail_followers.py b/addons/mail/models/mail_followers.py index 9bd8015342f..59d6d5d4254 100644 --- a/addons/mail/models/mail_followers.py +++ b/addons/mail/models/mail_followers.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -import threading - from openerp import _, api, fields, models from openerp import tools @@ -73,132 +71,6 @@ class Notification(models.Model): if not cr.fetchone(): cr.execute('CREATE INDEX mail_notification_partner_id_read_starred_message_id ON mail_notification (partner_id, is_read, starred, message_id)') - def get_partners_to_email(self, message): - """ Return the list of partners to notify, based on their preferences. - - :param browse_record message: mail.message to notify - :param list partners_to_notify: optional list of partner ids restricting - the notifications to process - """ - notify_pids = [] - for notification in self: - if notification.is_read: - continue - partner = notification.partner_id - # Do not send to partners without email address defined - if not partner.email: - continue - # Do not send to partners having same email address than the author (can cause loops or bounce effect due to messy database) - if message.author_id and message.author_id.email == partner.email: - continue - # Partner does not want to receive any emails or is opt-out - if partner.notify_email == 'none': - continue - notify_pids.append(partner.id) - return notify_pids - - @api.model - def get_signature_footer(self, user_id, res_model=None, res_id=None, user_signature=True): - """ Format a standard footer for notification emails (such as pushed messages - notification or invite emails). - Format: -

--
- Administrator -

-
- Sent from Your Company using Odoo. -
- """ - footer = "" - if not user_id: - return footer - - # add user signature - user = self.env.user - if user_signature: - if self.env.user.signature: - signature = user.signature - else: - signature = "--
%s" % user.name - footer = tools.append_content_to_html(footer, signature, plaintext=False) - - # add company signature - if user.company_id.website: - website_url = ('http://%s' % user.company_id.website) if not user.company_id.website.lower().startswith(('http:', 'https:')) \ - else user.company_id.website - company = "%s" % (website_url, user.company_id.name) - else: - company = user.company_id.name - sent_by = _('Sent by %(company)s using %(odoo)s') - - signature_company = '
%s' % (sent_by % { - 'company': company, - 'odoo': "Odoo" - }) - footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div') - - return footer - - def update_message_notification(self, message, partners): - # update existing notifications - self.write({'is_read': False}) - - # create new notifications - new_notif_ids = self.env['mail.notification'] - for new_pid in partners - self.mapped('partner_id'): - new_notif_ids |= self.create({'message_id': message.id, 'partner_id': new_pid.id, 'is_read': False}) - return new_notif_ids - - @api.multi - def _notify_email(self, message, force_send=False, user_signature=True): - - # compute partners - email_pids = self.get_partners_to_email(message) - if not email_pids: - return True - - # compute email body (signature, company data) - body_html = message.body - # add user signature except for mail.channels, where users are usually adding their own signatures already - user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None - signature_company = self.get_signature_footer(user_id, res_model=message.model, res_id=message.res_id, user_signature=(user_signature and message.model != 'mail.channel')) - if signature_company: - body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div') - - # compute email references - references = message.parent_id.message_id if message.parent_id else False - - # custom values - custom_values = dict() - if message.model and message.res_id and self.pool.get(message.model) and hasattr(self.pool[message.model], 'message_get_email_values'): - custom_values = self.env[message.model].browse(message.res_id).message_get_email_values(message) - - # create email values - max_recipients = 50 - chunks = [email_pids[x:x + max_recipients] for x in xrange(0, len(email_pids), max_recipients)] - emails = self.env['mail.mail'] - for chunk in chunks: - mail_values = { - 'mail_message_id': message.id, - 'auto_delete': self._context.get('mail_auto_delete', True), - 'mail_server_id': self._context.get('mail_server_id', False), - 'body_html': body_html, - 'recipient_ids': [(4, id) for id in chunk], - 'references': references, - } - mail_values.update(custom_values) - emails |= self.env['mail.mail'].create(mail_values) - # NOTE: - # 1. for more than 50 followers, use the queue system - # 2. do not send emails immediately if the registry is not loaded, - # to prevent sending email during a simple update of the database - # using the command-line. - if force_send and len(chunks) < 2 and \ - (not self.pool._init or - getattr(threading.currentThread(), 'testing', False)): - emails.send() - return True - @api.model def _notify(self, message, recipients=None, force_send=False, user_signature=True): """ Send by email the notification depending on the user preferences @@ -211,14 +83,22 @@ class Notification(models.Model): :param bool user_signature: if True, the generated mail.mail body is the body of the related mail.message with the author's signature """ - notif_ids = self.sudo().search([('message_id', '=', message.id), ('partner_id', 'in', recipients.ids)]) - - # update or create notifications - new_notif_ids = notif_ids.update_message_notification(message, recipients) # tde check: sudo - # mail_notify_noemail (do not send email) or no partner_ids: do not send, return if self.env.context.get('mail_notify_noemail'): return True + if not recipients: + recipients = message.partner_ids - # browse as SUPERUSER_ID because of access to res_partner not necessarily allowed - new_notif_ids._notify_email(message, force_send, user_signature) # tde check this one too + notifications = self.env['mail.notification'].sudo().search( + [('message_id', '=', message.id), ('partner_id', 'in', recipients.ids)]) + notifications.write({'is_read': False}) + new_notifications = self.env['mail.notification'].sudo() + for new_partner in recipients - notifications.mapped('partner_id'): + new_notifications |= self.env['mail.notification'].sudo().create({ + 'message_id': message.id, + 'partner_id': new_partner.id, + 'is_read': False}) + new_recipients = new_notifications.mapped('partner_id') + + # notify + new_recipients._notify(message, force_send=force_send, user_signature=user_signature) diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py index af0708e3434..25f19dcfaff 100644 --- a/addons/mail/models/res_partner.py +++ b/addons/mail/models/res_partner.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- -from openerp import _, api, fields, models +import threading + +from openerp import _, api, fields, models, tools class Partner(models.Model): @@ -33,3 +35,135 @@ class Partner(models.Model): @api.multi def message_get_default_recipients(self): return dict((res_id, {'partner_ids': [res_id], 'email_to': False, 'email_cc': False}) for res_id in self.ids) + + def get_partners_to_email(self, message, recipients): + """ Return the list of partners to notify, based on their preferences. + + :param browse_record message: mail.message to notify + :param record set recipients: recipients + """ + email_recipients = self.env['res.partner'] + for partner in recipients: + # Do not send to partners without email address defined + if not partner.email: + continue + # Do not send to partners having same email address than the author (can cause loops or bounce effect due to messy database) + if message.author_id and message.author_id.email == partner.email: + continue + # Partner does not want to receive any emails or is opt-out + if partner.notify_email == 'none': + continue + email_recipients |= partner + return email_recipients + + @api.model + def get_signature_footer(self, user_id, res_model=None, res_id=None, user_signature=True): + """ Format a standard footer for notification emails (such as pushed messages + notification or invite emails). + Format: +

--
+ Administrator +

+
+ Sent from Your Company using Odoo. +
+ """ + footer = "" + if not user_id: + return footer + + # add user signature + user = self.env.user + if user_signature: + if self.env.user.signature: + signature = user.signature + else: + signature = "--
%s" % user.name + footer = tools.append_content_to_html(footer, signature, plaintext=False) + + # add company signature + if user.company_id.website: + website_url = ('http://%s' % user.company_id.website) if not user.company_id.website.lower().startswith(('http:', 'https:')) \ + else user.company_id.website + company = "%s" % (website_url, user.company_id.name) + else: + company = user.company_id.name + sent_by = _('Sent by %(company)s using %(odoo)s') + + signature_company = '
%s' % (sent_by % { + 'company': company, + 'odoo': "Odoo" + }) + footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div') + + return footer + + @api.multi + def _notify_email(self, message, force_send=False, user_signature=True): + # compute partners + if not self.ids: + return True + email_pids = self.ids + # rebrowse as sudo to avoid access rigths on author, user, ... -> portal / public goes through this method + message_sudo = message.sudo() + + # compute email body (signature, company data) + body_html = message_sudo.body + # add user signature except for mail.channels, where users are usually adding their own signatures already + user_id = message_sudo.author_id and message_sudo.author_id.user_ids and message_sudo.author_id.user_ids[0] and message_sudo.author_id.user_ids[0].id or None + signature_company = self.get_signature_footer(user_id, res_model=message_sudo.model, res_id=message_sudo.res_id, user_signature=(user_signature and message_sudo.model != 'mail.channel')) + if signature_company: + body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div') + + # compute email references + references = message_sudo.parent_id.message_id if message_sudo.parent_id else False + + # custom values + custom_values = dict() + if message_sudo.model and message_sudo.res_id and self.pool.get(message_sudo.model) and hasattr(self.pool[message_sudo.model], 'message_get_email_values'): + custom_values = self.env[message_sudo.model].browse(message_sudo.res_id).message_get_email_values(message_sudo) + + # create email values + max_recipients = 50 + chunks = [email_pids[x:x + max_recipients] for x in xrange(0, len(email_pids), max_recipients)] + emails = self.env['mail.mail'] + for chunk in chunks: + mail_values = { + 'mail_message_id': message_sudo.id, + 'auto_delete': self._context.get('mail_auto_delete', True), + 'mail_server_id': self._context.get('mail_server_id', False), + 'body_html': body_html, + 'recipient_ids': [(4, id) for id in chunk], + 'references': references, + } + mail_values.update(custom_values) + emails |= self.env['mail.mail'].create(mail_values) + # NOTE: + # 1. for more than 50 followers, use the queue system + # 2. do not send emails immediately if the registry is not loaded, + # to prevent sending email during a simple update of the database + # using the command-line. + if force_send and len(chunks) < 2 and \ + (not self.pool._init or + getattr(threading.currentThread(), 'testing', False)): + emails.send() + return True + + @api.multi + def _notify(self, message, force_send=False, user_signature=True): + """ Send by email the notification depending on the user preferences + + :param list partners_to_notify: optional list of partner ids restricting + the notifications to process + :param bool force_send: if True, the generated mail.mail is + immediately sent after being created, as if the scheduler + was executed for this message only. + :param bool user_signature: if True, the generated mail.mail body is + the body of the related mail.message with the author's signature + """ + if self.ids: + recipients = self + else: + recipients = message.notified_partner_ids + email_recipients = self.get_partners_to_email(message, recipients) + email_recipients._notify_email(message, force_send=force_send, user_signature=user_signature) diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py index ed04e43ec5a..0d0dd361e24 100644 --- a/addons/mail/wizard/invite.py +++ b/addons/mail/wizard/invite.py @@ -48,7 +48,7 @@ class Invite(models.TransientModel): if wizard.send_mail and wizard.message and not wizard.message == '
': # when deleting the message, cleditor keeps a
# add signature # FIXME 8.0: use notification_email_send, send a wall message and let mail handle email notification + message box - signature_company = self.env['mail.notification'].get_signature_footer(user_id=self._uid, res_model=wizard.res_model, res_id=wizard.res_id) + signature_company = self.env['res.partner'].get_signature_footer(user_id=self._uid, res_model=wizard.res_model, res_id=wizard.res_id) wizard.message = tools.append_content_to_html(wizard.message, signature_company, plaintext=False, container_tag='div') # send mail to new followers