:param browse_record partner: specific recipient partner
"""
body = mail.body_html
+
+ # add footer
+ body_footer = self.send_get_mail_body_footer(cr, uid, mail, partner=partner, context=context)
+ body = tools.append_content_to_html(body, body_footer, plaintext=False, container_tag='div')
++
+ # generate footer
+ link = self._get_partner_access_link(cr, uid, mail, partner, context=context)
+ if link:
+ body = tools.append_content_to_html(body, link, plaintext=False, container_tag='div')
return body
- def send_get_mail_reply_to(self, cr, uid, mail, partner=None, context=None):
- """ Return a specific ir_email reply_to.
-
- :param browse_record mail: mail.mail browse_record
- :param browse_record partner: specific recipient partner
- """
- if mail.reply_to:
- return mail.reply_to
- email_reply_to = False
-
- # if model and res_id: try to use ``message_get_reply_to`` that returns the document alias
- if mail.model and mail.res_id and hasattr(self.pool.get(mail.model), 'message_get_reply_to'):
- email_reply_to = self.pool.get(mail.model).message_get_reply_to(cr, uid, [mail.res_id], context=context)[0]
- # no alias reply_to -> reply_to will be the email_from, only the email part
- if not email_reply_to and mail.email_from:
- emails = tools.email_split(mail.email_from)
- if emails:
- email_reply_to = emails[0]
-
- # format 'Document name <email_address>'
- if email_reply_to and mail.model and mail.res_id:
- document_name = self.pool.get(mail.model).name_get(cr, SUPERUSER_ID, [mail.res_id], context=context)[0]
- if document_name:
- # sanitize document name
- sanitized_doc_name = re.sub(r'[^\w+.]+', '-', document_name[1])
- # generate reply to
- email_reply_to = _('"Followers of %s" <%s>') % (sanitized_doc_name, email_reply_to)
-
- return email_reply_to
-
def send_get_email_dict(self, cr, uid, mail, partner=None, context=None):
""" Return a dictionary for specific email values, depending on a
partner, or generic to the whole recipients given by mail.email_to.
return [('message_unread', '=', True)]
return []
+ def _garbage_collect_attachments(self, cr, uid, context=None):
+ """ Garbage collect lost mail attachments. Those are attachments
+ - linked to res_model 'mail.compose.message', the composer wizard
+ - with res_id 0, because they were created outside of an existing
+ wizard (typically user input through Chatter or reports
+ created on-the-fly by the templates)
+ - unused since at least one day (create_date and write_date)
+ """
+ limit_date = datetime.datetime.utcnow() - datetime.timedelta(days=1)
+ limit_date_str = datetime.datetime.strftime(limit_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
+ ir_attachment_obj = self.pool.get('ir.attachment')
+ attach_ids = ir_attachment_obj.search(cr, uid, [
+ ('res_model', '=', 'mail.compose.message'),
+ ('res_id', '=', 0),
+ ('create_date', '<', limit_date_str),
+ ('write_date', '<', limit_date_str),
+ ], context=context)
+ ir_attachment_obj.unlink(cr, uid, attach_ids, context=context)
+ return True
+
+ def message_redirect_get_inbox_action_xml_id(self, cr, uid, context=None):
+ """ When redirecting towards the Inbox, choose which action xml_id has
+ to be fetched. This method is meant to be inherited, at least in portal
+ because portal users have a different Inbox action than classic users. """
+ return ('mail', 'action_mail_inbox_feeds')
+
+ def message_redirect_action(self, cr, uid, context=None):
+ """ For a given message, return an action that either
+ - opens the form view of the related document if model, res_id, and
+ read access to the document
+ - opens the Inbox with a default search on the conversation if model,
+ res_id
+ - opens the Inbox with context propagated
++
+ """
+ if context is None:
+ context = {}
+
+ # default action is the Inbox action
+ self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
+ act_model, act_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, *self.message_redirect_get_inbox_action_xml_id(cr, uid, context=context))
+ action = self.pool.get(act_model).read(cr, uid, act_id, [])
+
+ # if msg_id specified: try to redirect to the document or fallback on the Inbox
+ msg_id = context.get('params', {}).get('message_id')
+ if not msg_id:
+ return action
+ msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context)
+ if msg.model and msg.res_id and self.pool.get(msg.model).check_access_rights(cr, uid, 'read', raise_exception=False):
+ try:
+ self.pool.get(msg.model).check_access_rule(cr, uid, [msg.res_id], 'read', context=context)
+ action = {
+ 'type': 'ir.actions.act_window',
+ 'res_model': msg.model,
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'views': [(msg.res_id, 'form')],
+ 'target': 'current',
+ 'res_id': msg.res_id,
+ }
+ except osv.except_osv:
+ action.update({
+ 'context': {
+ 'search_default_model': msg.model,
+ 'search_default_res_id': msg.res_id,
+ }
+ })
+ return action
+
#------------------------------------------------------
# Email specific
#------------------------------------------------------
class TestMailgateway(TestMailBase):
+ def test_00_partner_find_from_email(self):
+ """ Tests designed for partner fetch based on emails. """
+ cr, uid, user_raoul, group_pigs = self.cr, self.uid, self.user_raoul, self.group_pigs
+
+ # --------------------------------------------------
+ # Data creation
+ # --------------------------------------------------
+ # 1 - Partner ARaoul
+ p_a_id = self.res_partner.create(cr, uid, {'name': 'ARaoul', 'email': 'test@test.fr'})
+
+ # --------------------------------------------------
+ # CASE1: without object
+ # --------------------------------------------------
+
+ # Do: find partner with email -> first partner should be found
+ partner_info = self.mail_thread.message_find_partner_from_emails(cr, uid, None, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
+ self.assertEqual(partner_info['full_name'], 'Maybe Raoul <test@test.fr>',
+ 'mail_thread: message_find_partner_from_emails did not handle email')
+ self.assertEqual(partner_info['partner_id'], p_a_id,
+ 'mail_thread: message_find_partner_from_emails wrong partner found')
+
+ # Data: add some data about partners
+ # 2 - User BRaoul
+ p_b_id = self.res_partner.create(cr, uid, {'name': 'BRaoul', 'email': 'test@test.fr', 'user_ids': [(4, user_raoul.id)]})
+
+ # Do: find partner with email -> first user should be found
+ partner_info = self.mail_thread.message_find_partner_from_emails(cr, uid, None, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
+ self.assertEqual(partner_info['partner_id'], p_b_id,
+ 'mail_thread: message_find_partner_from_emails wrong partner found')
+
+ # --------------------------------------------------
+ # CASE1: with object
+ # --------------------------------------------------
+
+ # Do: find partner in group where there is a follower with the email -> should be taken
+ self.mail_group.message_subscribe(cr, uid, [group_pigs.id], [p_b_id])
+ partner_info = self.mail_group.message_find_partner_from_emails(cr, uid, group_pigs.id, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
+ self.assertEqual(partner_info['partner_id'], p_b_id,
+ 'mail_thread: message_find_partner_from_emails wrong partner found')
+
+ @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm')
- def test_00_message_process(self):
+ def test_10_message_process(self):
""" Testing incoming emails processing. """
cr, uid, user_raoul = self.cr, self.uid, self.user_raoul
self.assertEqual(msg.body, '<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>',
'message_process: plaintext incoming email incorrectly parsed')
+ @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm')
- def test_10_thread_parent_resolution(self):
+ def test_20_thread_parent_resolution(self):
""" Testing parent/child relationships are correctly established when processing incoming mails """
cr, uid = self.cr, self.uid