# along with this program. If not, see <http://www.gnu.org/licenses/>
#
##############################################################################
-
-from osv import osv
-from osv import fields
-import tools
+from openerp.osv import osv, fields
+from openerp import tools, SUPERUSER_ID
+from openerp.tools.translate import _
+from openerp.tools.mail import plaintext2html
class mail_followers(osv.Model):
""" mail_followers holds the data related to the follow mechanism inside
help='Id of the followed resource'),
'partner_id': fields.many2one('res.partner', string='Related Partner',
ondelete='cascade', required=True, select=1),
+ 'subtype_ids': fields.many2many('mail.message.subtype', string='Subtype',
+ help="Message subtypes followed, meaning subtypes that will be pushed onto the user's Wall."),
}
_columns = {
'partner_id': fields.many2one('res.partner', string='Contact',
ondelete='cascade', required=True, select=1),
- 'read': fields.boolean('Read'),
+ 'read': fields.boolean('Read', select=1),
+ 'starred': fields.boolean('Starred', select=1,
+ help='Starred message that goes into the todo mailbox'),
+ 'message_id': fields.many2one('mail.message', string='Message',
+ ondelete='cascade', required=True, select=1),
}
_defaults = {
'read': False,
+ 'starred': False,
}
- def create(self, cr, uid, vals, context=None):
- """ Override of create to check that we can not create a notification
- for a message the user can not read. """
- if self.pool.get('mail.message').check_access_rights(cr, uid, 'read'):
- return super(mail_notification, self).create(cr, uid, vals, context=context)
- return False
-
- def notify(self, cr, uid, partner_ids, msg_id, context=None):
- """ Send by email the notification depending on the user preferences """
- context = context or {}
- # mail_noemail (do not send email) or no partner_ids: do not send, return
- if context.get('mail_noemail') or not partner_ids:
- return True
-
- mail_mail_obj = self.pool.get('mail.mail')
- msg_obj = self.pool.get('mail.message')
- msg = msg_obj.browse(cr, uid, msg_id, context=context)
-
- # add signature
- body_html = msg.body
- signature = msg.author_id and msg.author_id.user_ids[0].signature or ''
- insertion_point = body_html.find('</html>')
- if insertion_point > -1:
- insertion_point = body_html.find('</html>')
- body_html = body_html[:insertion_point] + '<div>%s</div>' % tools.ustr(signature) + body_html[insertion_point:]
- else:
- body_html = body_html + '<div>%s</div>' % tools.ustr(signature)
+ def init(self, cr):
+ cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('mail_notification_partner_id_read_starred_message_id',))
+ if not cr.fetchone():
+ cr.execute('CREATE INDEX mail_notification_partner_id_read_starred_message_id ON mail_notification (partner_id, read, starred, message_id)')
- towrite = {
- 'mail_message_id': msg.id,
- 'email_to': [],
- 'auto_delete': False,
- 'body_html': body_html,
- }
+ def get_partners_to_email(self, cr, uid, ids, message, context=None):
+ """ Return the list of partners to notify, based on their preferences.
- for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context):
- # Do not send an email to the writer
- if partner.user_ids and partner.user_ids[0].id == uid:
+ :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.browse(cr, uid, ids, context=context):
+ if notification.read:
continue
+ partner = notification.partner_id
# Do not send to partners without email address defined
if not partner.email:
continue
- # Partner does not want to receive any emails
+ # 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.notification_email_send == 'none':
continue
# Partner wants to receive only emails and comments
- if partner.notification_email_send == 'comment' and msg.type not in ('email', 'comment'):
+ if partner.notification_email_send == 'comment' and message.type not in ('email', 'comment'):
continue
# Partner wants to receive only emails
- if partner.notification_email_send == 'email' and msg.type != 'email':
+ if partner.notification_email_send == 'email' and message.type != 'email':
continue
- if partner.email not in towrite['email_to']:
- towrite['email_to'].append(partner.email)
- towrite['email_to'] = ', '.join(towrite['email_to'])
+ notify_pids.append(partner.id)
+ return notify_pids
+
+ def get_signature_footer(self, cr, uid, user_id, res_model=None, res_id=None, context=None):
+ """ Format a standard footer for notification emails (such as pushed messages
+ notification or invite emails).
+ Format:
+ <p>--<br />
+ Administrator
+ </p>
+ <div>
+ <small>Sent by <a ...>Your Company</a> using <a ...>OpenERP</a>.</small> OR
+ <small>Sent by Administrator using <a ...>OpenERP</a>.</small>
+ </div>
+ """
+ footer = ""
+ if not user_id:
+ return footer
+
+ # add user signature
+ user = self.pool.get("res.users").browse(cr, SUPERUSER_ID, [user_id], context=context)[0]
+ if user.signature:
+ signature = plaintext2html(user.signature)
+ else:
+ signature = "--<br />%s" % user.name
+ footer = tools.append_content_to_html(footer, signature, plaintext=False, container_tag='p')
+
+ # 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 %(openerp)s.')
+ signature_company = '<small>%s</small>' % (sent_by % {
+ 'company': company,
+ 'openerp': "<a style='color:inherit' href='https://www.openerp.com/'>OpenERP</a>"
+ })
+ footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div')
+
+ return footer
+
+ def update_message_notification(self, cr, uid, ids, message_id, partner_ids, context=None):
+ existing_pids = set()
+ new_pids = set()
+ new_notif_ids = []
+
+ for notification in self.browse(cr, uid, ids, context=context):
+ existing_pids.add(notification.partner_id.id)
- email_notif_id = mail_mail_obj.create(cr, uid, towrite, context=context)
- mail_mail_obj.send(cr, uid, [email_notif_id], context=context)
+ # update existing notifications
+ self.write(cr, uid, ids, {'read': False}, context=context)
+
+ # create new notifications
+ new_pids = set(partner_ids) - existing_pids
+ for new_pid in new_pids:
+ new_notif_ids.append(self.create(cr, uid, {'message_id': message_id, 'partner_id': new_pid, 'read': False}, context=context))
+ return new_notif_ids
+
+ def _notify_email(self, cr, uid, ids, message_id, force_send=False, user_signature=True, context=None):
+ message = self.pool['mail.message'].browse(cr, SUPERUSER_ID, message_id, context=context)
+
+ # compute partners
+ email_pids = self.get_partners_to_email(cr, uid, ids, message, context=None)
+ if not email_pids:
+ return True
+
+ # compute email body (signature, company data)
+ body_html = message.body
+ 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
+ if user_signature:
+ signature_company = self.get_signature_footer(cr, uid, user_id, res_model=message.model, res_id=message.res_id, context=context)
+ 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
+
+ # create email values
+ mail_values = {
+ 'mail_message_id': message.id,
+ 'auto_delete': True,
+ 'body_html': body_html,
+ 'recipient_ids': [(4, id) for id in email_pids],
+ 'references': references,
+ }
+ email_notif_id = self.pool.get('mail.mail').create(cr, uid, mail_values, context=context)
+ if force_send:
+ self.pool.get('mail.mail').send(cr, uid, [email_notif_id], context=context)
return True
+
+ def _notify(self, cr, uid, message_id, partners_to_notify=None, context=None,
+ 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
+ """
+ notif_ids = self.search(cr, SUPERUSER_ID, [('message_id', '=', message_id), ('partner_id', 'in', partners_to_notify)], context=context)
+
+ # update or create notifications
+ new_notif_ids = self.update_message_notification(cr, SUPERUSER_ID, notif_ids, message_id, partners_to_notify, context=context)
+
+ # mail_notify_noemail (do not send email) or no partner_ids: do not send, return
+ if context and context.get('mail_notify_noemail'):
+ return True
+
+ # browse as SUPERUSER_ID because of access to res_partner not necessarily allowed
+ self._notify_email(cr, SUPERUSER_ID, new_notif_ids, message_id, force_send, user_signature, context=context)