[MOV] mail: move code for email notification
Move the notification management from mail.notification to res.partner model. Those methods belong more to the partner model, as they work on partners. Moreover with the upcoming new model for NewChatter notification will be heavily refactored.
This commit is contained in:
@@ -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:
|
||||
<p>--<br />
|
||||
Administrator
|
||||
</p>
|
||||
<div>
|
||||
<small>Sent from <a ...>Your Company</a> using <a ...>Odoo</a>.</small>
|
||||
</div>
|
||||
"""
|
||||
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 = "--<br />%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 = "<a style='color:inherit' href='%s'>%s</a>" % (website_url, user.company_id.name)
|
||||
else:
|
||||
company = user.company_id.name
|
||||
sent_by = _('Sent by %(company)s using %(odoo)s')
|
||||
|
||||
signature_company = '<br /><small>%s</small>' % (sent_by % {
|
||||
'company': company,
|
||||
'odoo': "<a style='color:inherit' href='https://www.odoo.com/'>Odoo</a>"
|
||||
})
|
||||
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)
|
||||
|
||||
@@ -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:
|
||||
<p>--<br />
|
||||
Administrator
|
||||
</p>
|
||||
<div>
|
||||
<small>Sent from <a ...>Your Company</a> using <a ...>Odoo</a>.</small>
|
||||
</div>
|
||||
"""
|
||||
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 = "--<br />%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 = "<a style='color:inherit' href='%s'>%s</a>" % (website_url, user.company_id.name)
|
||||
else:
|
||||
company = user.company_id.name
|
||||
sent_by = _('Sent by %(company)s using %(odoo)s')
|
||||
|
||||
signature_company = '<br /><small>%s</small>' % (sent_by % {
|
||||
'company': company,
|
||||
'odoo': "<a style='color:inherit' href='https://www.odoo.com/'>Odoo</a>"
|
||||
})
|
||||
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)
|
||||
|
||||
@@ -48,7 +48,7 @@ class Invite(models.TransientModel):
|
||||
if wizard.send_mail and wizard.message and not wizard.message == '<br>': # when deleting the message, cleditor keeps a <br>
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user