def message_get_reply_to(self, cr, uid, ids, context=None):
""" Override to get the reply_to of the parent project. """
return [lead.section_id.message_get_reply_to()[0] if lead.section_id else False
- for lead in self.browse(cr, uid, ids, context=context)]
+ for lead in self.browse(cr, SUPERUSER_ID, ids, context=context)]
+ def _get_formview_action(self, cr, uid, id, context=None):
+ action = super(crm_lead, self)._get_formview_action(cr, uid, id, context=context)
+ obj = self.browse(cr, uid, id, context=context)
+ if obj.type == 'opportunity':
+ model, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
+ action.update({
+ 'views': [(view_id, 'form')],
+ })
+ return action
+
def message_get_suggested_recipients(self, cr, uid, ids, context=None):
recipients = super(crm_lead, self).message_get_suggested_recipients(cr, uid, ids, context=context)
- for lead in self.browse(cr, uid, ids, context=context):
- if lead.partner_id:
- self._message_add_suggested_recipient(cr, uid, recipients, lead, partner=lead.partner_id, reason=_('Customer'))
- elif lead.email_from:
- self._message_add_suggested_recipient(cr, uid, recipients, lead, email=lead.email_from, reason=_('Customer Email'))
+ try:
+ for lead in self.browse(cr, uid, ids, context=context):
+ if lead.partner_id:
+ self._message_add_suggested_recipient(cr, uid, recipients, lead, partner=lead.partner_id, reason=_('Customer'))
+ elif lead.email_from:
+ self._message_add_suggested_recipient(cr, uid, recipients, lead, email=lead.email_from, reason=_('Customer Email'))
+ except (osv.except_osv, orm.except_orm): # no read access rights -> just ignore suggested recipients because this imply modifying followers
+ pass
return recipients
def message_new(self, cr, uid, msg, custom_values=None, context=None):
:param browse_record mail: mail.mail browse_record
:param browse_record partner: specific recipient partner
"""
- if force or (not mail.subject and mail.model and mail.res_id):
+ if (force or not mail.subject) and mail.record_name:
return 'Re: %s' % (mail.record_name)
+ elif (force or not mail.subject) and mail.parent_id and mail.parent_id.subject:
+ return 'Re: %s' % (mail.parent_id.subject)
return mail.subject
- def send_get_mail_body_footer(self, cr, uid, mail, partner=None, context=None):
- """ Return a specific footer for the ir_email body. The main purpose of this method
- is to be inherited by Portal, to add modify the link for signing in, in
- each notification email a partner receives.
- """
- body_footer = ""
- # partner is a user, link to a related document (incentive to install portal)
- if partner and partner.user_ids and mail.model and mail.res_id \
- and self.check_access_rights(cr, partner.user_ids[0].id, 'read', raise_exception=False):
- related_user = partner.user_ids[0]
- try:
- self.pool[mail.model].check_access_rule(cr, related_user.id, [mail.res_id], 'read', context=context)
- base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
- # the parameters to encode for the query and fragment part of url
- query = {'db': cr.dbname}
- fragment = {
- 'login': related_user.login,
- 'model': mail.model,
- 'id': mail.res_id,
- }
- url = urljoin(base_url, "?%s#%s" % (urlencode(query), urlencode(fragment)))
- body_footer = _("""<small>Access this document <a style='color:inherit' href="%s">directly in OpenERP</a></small>""") % url
- except except_orm, e:
- pass
- return body_footer
-
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):
""" Return a specific ir_email body. The main purpose of this method
is to be inherited to add custom content depending on some module.
self.assertEqual(partner_info['partner_id'], p_b_id,
'mail_thread: message_find_partner_from_emails wrong partner found')
+ def test_05_mail_message_mail_mail(self):
+ """ Tests designed for testing email values based on mail.message, aliases, ... """
+ cr, uid = self.cr, self.uid
+
+ # Data: clean catchall domain
+ param_ids = self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.domain')])
+ self.registry('ir.config_parameter').unlink(cr, uid, param_ids)
+
+ # Do: create a mail_message with a reply_to, without message-id
+ msg_id = self.mail_message.create(cr, uid, {'subject': 'Subject', 'body': 'Body', 'reply_to': 'custom@example.com'})
+ msg = self.mail_message.browse(cr, uid, msg_id)
+ # Test: message content
+ self.assertIn('reply_to', msg.message_id,
+ 'mail_message: message_id should be specific to a mail_message with a given reply_to')
+ self.assertEqual('custom@example.com', msg.reply_to,
+ 'mail_message: incorrect reply_to')
+ # Do: create a mail_mail with the previous mail_message and specified reply_to
+ mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'reply_to': 'other@example.com', 'state': 'cancel'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertEqual(mail.reply_to, 'other@example.com',
+ 'mail_mail: reply_to should be equal to the one coming from creation values')
+ # Do: create a mail_mail with the previous mail_message
+ mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertEqual(mail.reply_to, msg.reply_to,
+ 'mail_mail: reply_to should be equal to the one coming from the mail_message')
+
+ # Do: create a mail_message without a reply_to
+ msg_id = self.mail_message.create(cr, uid, {'subject': 'Subject', 'body': 'Body', 'model': 'mail.group', 'res_id': self.group_pigs_id, 'email_from': False})
+ msg = self.mail_message.browse(cr, uid, msg_id)
+ # Test: message content
+ self.assertIn('mail.group', msg.message_id,
+ 'mail_message: message_id should contain model')
+ self.assertIn('%s' % self.group_pigs_id, msg.message_id,
+ 'mail_message: message_id should contain res_id')
+ self.assertFalse(msg.reply_to,
+ 'mail_message: should not generate a reply_to address when not specified')
+ # Do: create a mail_mail based on the previous mail_message
+ mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertFalse(mail.reply_to,
+ 'mail_mail: reply_to should not have been guessed')
+ # Update message
+ self.mail_message.write(cr, uid, [msg_id], {'email_from': 'someone@example.com'})
+ msg.refresh()
+ # Do: create a mail_mail based on the previous mail_message
+ mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertEqual(mail.reply_to, msg.email_from,
+ 'mail_mail: reply_to should equal to mail_message.email_from when having no document or default alias')
+
+ # Data: set catchall domain
+ self.registry('ir.config_parameter').set_param(cr, uid, 'mail.catchall.domain', 'schlouby.fr')
+ self.registry('ir.config_parameter').unlink(cr, uid, self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.alias')]))
+
+ # Do: create a mail_mail based on the previous mail_message
+ mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertEqual(mail.reply_to, '"Followers of Pigs" <group+pigs@schlouby.fr>',
+ 'mail_mail: reply_to should equal the mail.group alias')
+
+ # Update message
+ self.mail_message.write(cr, uid, [msg_id], {'res_id': False, 'email_from': 'someone@schlouby.fr'})
+ msg.refresh()
+ # Do: create a mail_mail based on the previous mail_message
+ mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertEqual(mail.reply_to, msg.email_from,
+ 'mail_mail: reply_to should equal the mail_message email_from')
+
+ # Data: set catchall alias
+ self.registry('ir.config_parameter').set_param(self.cr, self.uid, 'mail.catchall.alias', 'gateway')
+
+ # Do: create a mail_mail based on the previous mail_message
+ mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertEqual(mail.reply_to, 'gateway@schlouby.fr',
+ 'mail_mail: reply_to should equal the catchall email alias')
+
+ # Do: create a mail_mail
+ mail_id = self.mail_mail.create(cr, uid, {'state': 'cancel'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertEqual(mail.reply_to, 'gateway@schlouby.fr',
+ 'mail_mail: reply_to should equal the catchall email alias')
+
+ # Do: create a mail_mail
+ mail_id = self.mail_mail.create(cr, uid, {'state': 'cancel', 'reply_to': 'someone@example.com'})
+ mail = self.mail_mail.browse(cr, uid, mail_id)
+ # Test: mail_mail content
+ self.assertEqual(mail.reply_to, 'someone@example.com',
+ 'mail_mail: reply_to should equal the rpely_to given to create')
+
+ @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm')
def test_10_message_process(self):
""" Testing incoming emails processing. """
cr, uid, user_raoul = self.cr, self.uid, self.user_raoul
##############################################################################
import portal
+import mail_thread
import mail_mail
+ import mail_message
import wizard
import acquirer
""" Update of mail_mail class, to add the signin URL to notifications. """
_inherit = 'mail.mail'
- def send_get_mail_body_footer(self, cr, uid, mail, partner=None, context=None):
- """ add a signin link inside the body of a mail.mail
- :param mail: mail.mail browse_record
- :param partner: browse_record of the specific recipient partner
- :return: the resulting body_html
+ def _get_partner_access_link(self, cr, uid, mail, partner=None, context=None):
+ """ Generate URLs for links in mails:
+ - partner is not an user: signup_url
+ - partner is an user: fallback on classic URL
"""
+ if context is None:
+ context = {}
+ partner_obj = self.pool.get('res.partner')
if partner and not partner.user_ids:
- contex_signup = dict(context or {}, signup_valid=True)
- partner = self.pool.get('res.partner').browse(cr, SUPERUSER_ID, partner.id, context=contex_signup)
- return _("""<small>Access your messages and documents through <a style='color:inherit' href="%s">our Customer Portal</a></small>""") % partner.signup_url
+ contex_signup = dict(context, signup_valid=True)
+ signup_url = partner_obj._get_signup_url_for_action(cr, SUPERUSER_ID, [partner.id],
+ action='login', model=mail.model, res_id=mail.res_id,
+ context=contex_signup)[partner.id]
+ return _("""<small>Access your messages and documents through <a style='color:inherit' href="%s">our Customer Portal</a></small>""") % signup_url
else:
- return super(mail_mail, self).send_get_mail_body_footer(cr, uid, mail, partner=partner, context=context)
+ return super(mail_mail, self)._get_partner_access_link(cr, uid, mail, partner=partner, context=context)
self.assertTrue(partner_carine.signup_url in sent_email.get('body'),
'invite: body of invitation email does not contain signup url')
- def test_20_message_read(self):
+ def test_20_notification_url(self):
+ """ Tests designed to test the URL added in notification emails. """
+ cr, uid, group_pigs = self.cr, self.uid, self.group_pigs
+
+ # Partner data
+ partner_raoul = self.res_partner.browse(cr, uid, self.partner_raoul_id)
+ partner_bert_id = self.res_partner.create(cr, uid, {'name': 'bert'})
+ partner_bert = self.res_partner.browse(cr, uid, partner_bert_id)
+ # Mail data
+ mail_mail_id = self.mail_mail.create(cr, uid, {'state': 'exception'})
+ mail = self.mail_mail.browse(cr, uid, mail_mail_id)
+
+ # Test: link for nobody -> None
+ url = self.mail_mail._get_partner_access_link(cr, uid, mail)
+ self.assertEqual(url, None,
+ 'notification email: mails not send to a specific partner should not have any URL')
+
+ # Test: link for partner -> signup URL
+ url = self.mail_mail._get_partner_access_link(cr, uid, mail, partner=partner_bert)
+ self.assertIn(partner_bert.signup_url, url,
+ 'notification email: mails send to a not-user partner should contain the signup URL')
+
+ # Test: link for user -> signin
+ url = self.mail_mail._get_partner_access_link(cr, uid, mail, partner=partner_raoul)
+ self.assertIn('action=mail.action_mail_redirect', url,
+ 'notification email: link should contain the redirect action')
+ self.assertIn('login=%s' % partner_raoul.user_ids[0].login, url,
+ 'notification email: link should contain the user login')
+
+ @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm')
+ def test_21_inbox_redirection(self):
+ """ Tests designed to test the inbox redirection of emails notification URLs. """
+ cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs
+ model, act_id = self.ir_model_data.get_object_reference(cr, uid, 'mail', 'action_mail_inbox_feeds')
+ model, port_act_id = self.ir_model_data.get_object_reference(cr, uid, 'portal', 'action_mail_inbox_feeds_portal')
+ # Data: post a message on pigs
+ msg_id = self.group_pigs.message_post(body='My body', partner_ids=[self.partner_bert_id, self.partner_chell_id], type='comment', subtype='mail.mt_comment')
+
+ # No specific parameters -> should redirect to Inbox
+ action = self.mail_thread.message_redirect_action(cr, self.user_raoul_id, {'params': {}})
+ self.assertEqual(action.get('type'), 'ir.actions.client',
+ 'URL redirection: action without parameters should redirect to client action Inbox')
+ self.assertEqual(action.get('id'), act_id,
+ 'URL redirection: action without parameters should redirect to client action Inbox')
+
+ # Bert has read access to Pigs -> should redirect to form view of Pigs
+ action = self.mail_thread.message_redirect_action(cr, self.user_raoul_id, {'params': {'message_id': msg_id}})
+ self.assertEqual(action.get('type'), 'ir.actions.act_window',
+ 'URL redirection: action with message_id for read-accredited user should redirect to Pigs')
+ self.assertEqual(action.get('res_id'), group_pigs.id,
+ 'URL redirection: action with message_id for read-accredited user should redirect to Pigs')
+
+ # Bert has no read access to Pigs -> should redirect to Inbox
+ action = self.mail_thread.message_redirect_action(cr, self.user_bert_id, {'params': {'message_id': msg_id}})
+ self.assertEqual(action.get('type'), 'ir.actions.client',
+ 'URL redirection: action without parameters should redirect to client action Inbox')
+ self.assertEqual(action.get('id'), act_id,
+ 'URL redirection: action without parameters should redirect to client action Inbox')
+
+ # Chell has no read access to pigs -> should redirect to Portal Inbox
+ action = self.mail_thread.message_redirect_action(cr, self.user_chell_id, {'params': {'message_id': msg_id}})
+ self.assertEqual(action.get('type'), 'ir.actions.client',
+ 'URL redirection: action without parameters should redirect to client action Inbox')
+ self.assertEqual(action.get('id'), port_act_id,
+ 'URL redirection: action without parameters should redirect to client action Inbox')
+
++ def test_30_message_read(self):
+ cr, uid, group_port_id = self.cr, self.uid, self.group_port_id
+
+ # Data: custom subtypes
+ mt_group_public_id = self.mail_message_subtype.create(cr, uid, {'name': 'group_public', 'description': 'Group changed'})
+ self.ir_model_data.create(cr, uid, {'name': 'mt_group_public', 'model': 'mail.message.subtype', 'module': 'mail', 'res_id': mt_group_public_id})
+ # Data: post messages with various subtypes
+ msg1_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body1', type='comment', subtype='mail.mt_comment')
+ msg2_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body2', type='comment', subtype='mail.mt_group_public')
+ msg3_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body3', type='comment', subtype='mail.mt_comment')
+ msg4_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body4', type='comment')
+ msg5_id = self.mail_group.message_post(cr, uid, group_port_id, body='Body5', type='notification')
+
+ # Do: Chell search messages: should not see internal notes (comment without subtype)
+ msg_ids = self.mail_message.search(cr, self.user_chell_id, [('model', '=', 'mail.group'), ('res_id', '=', group_port_id)])
+ self.assertEqual(set(msg_ids), set([msg1_id, msg2_id, msg3_id, msg5_id]),
+ 'mail_message: portal user has access to messages he should not read')
+
+ # Do: Chell read messages she can read
+ self.mail_message.read(cr, self.user_chell_id, msg_ids, ['body', 'type', 'subtype_id'])
+
+ # Do: Chell read a message she should not be able to read
+ with self.assertRaises(except_orm):
+ self.mail_message.read(cr, self.user_chell_id, [msg4_id], ['body', 'type', 'subtype_id'])