[IMP] mail_tracking: Store To recipients and omit aliases

This commit is contained in:
Alexandre Díaz 2020-03-19 20:30:34 +01:00 committed by Jasmin Solanki
parent 103192362e
commit bedeb56759
10 changed files with 126 additions and 39 deletions

View File

@ -76,6 +76,9 @@ These are all available status icons:
.. |noemail| image:: https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/no_email.png .. |noemail| image:: https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/no_email.png
:width: 10px :width: 10px
.. |anonuser| image:: https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/anon_user.png
:width: 10px
|unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never' |unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never'
|waiting| **Waiting**: Waiting to be sent |waiting| **Waiting**: Waiting to be sent
@ -92,6 +95,8 @@ These are all available status icons:
|noemail| **No Email**: The partner doesn't have a defined email |noemail| **No Email**: The partner doesn't have a defined email
|anonuser| **No Partner**: The recipient doesn't have a defined partner
If you want to see all tracking emails and events you can go to If you want to see all tracking emails and events you can go to

View File

@ -9,3 +9,4 @@ from . import mail_tracking_event
from . import res_partner from . import res_partner
from . import mail_thread from . import mail_thread
from . import mail_resend_message from . import mail_resend_message
from . import mail_alias

View File

@ -0,0 +1,33 @@
# Copyright 2020 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, models, tools
class MailAlias(models.Model):
_inherit = "mail.alias"
@api.model
@tools.ormcache()
def get_aliases(self):
return {
x["display_name"]
for x in self.search_read([("alias_name", "!=", False)], ["display_name"])
}
@api.model_create_multi
def create(self, vals_list):
res = super().create(vals_list)
self.clear_caches()
return res
def write(self, vals):
res = super().write(vals)
if "alias_name" in vals:
self.clear_caches()
return res
def unlink(self):
res = super().unlink()
self.clear_caches()
return res

View File

@ -2,6 +2,8 @@
# Copyright 2019 Alexandre Díaz # Copyright 2019 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from email.utils import getaddresses
from odoo import _, api, fields, models from odoo import _, api, fields, models
from odoo.tools import email_split from odoo.tools import email_split
@ -13,6 +15,7 @@ class MailMessage(models.Model):
email_cc = fields.Char( email_cc = fields.Char(
"Cc", help="Additional recipients that receive a " '"Carbon Copy" of the e-mail' "Cc", help="Additional recipients that receive a " '"Carbon Copy" of the e-mail'
) )
email_to = fields.Char("To", help="Raw TO recipients")
mail_tracking_ids = fields.One2many( mail_tracking_ids = fields.One2many(
comodel_name="mail.tracking.email", comodel_name="mail.tracking.email",
inverse_name="mail_message_id", inverse_name="mail_message_id",
@ -105,11 +108,16 @@ class MailMessage(models.Model):
.sudo() .sudo()
.search([("mail_message_id", "=", message.id)]) .search([("mail_message_id", "=", message.id)])
) )
# Get Cc recipients # String to List
email_cc_list = email_split(message.email_cc) email_cc_list = self._drop_aliases(email_split(message.email_cc))
if any(email_cc_list): email_to_list = self._drop_aliases(email_split(message.email_to))
partners |= partners.search([("email", "in", email_cc_list)]) # Search related partners recipients
partners |= partners.search(
[("email", "in", email_cc_list + email_to_list)]
)
# Operate over set's instead of lists
email_cc_list = set(email_cc_list) email_cc_list = set(email_cc_list)
email_to_list = set(email_to_list) - email_cc_list
# Search all trackings for this message # Search all trackings for this message
for tracking in trackings: for tracking in trackings:
status = self._partner_tracking_status_get(tracking) status = self._partner_tracking_status_get(tracking)
@ -127,45 +135,66 @@ class MailMessage(models.Model):
} }
) )
if tracking.partner_id: if tracking.partner_id:
# Discard mails with tracking
email_cc_list.discard(tracking.partner_id.email) email_cc_list.discard(tracking.partner_id.email)
email_to_list.discard(tracking.partner_id.email)
partners_already |= tracking.partner_id partners_already |= tracking.partner_id
# Search all recipients for this message # Search all partner recipients for this message
if message.partner_ids: if message.partner_ids:
partners |= message.partner_ids partners |= message.partner_ids
if message.notified_partner_ids: if message.notified_partner_ids:
partners |= message.notified_partner_ids partners |= message.notified_partner_ids
# Remove recipients already included # Discard partner recipients already included
partners -= partners_already partners -= partners_already
tracking_unkown_values = { # Default tracking values
tracking_unknown_values = {
"status": "unknown", "status": "unknown",
"status_human": self._partner_tracking_status_human_get("unknown"), "status_human": self._partner_tracking_status_human_get("unknown"),
"error_type": False, "error_type": False,
"error_description": False, "error_description": False,
"tracking_id": False, "tracking_id": False,
} }
# Process tracking status of partner recipients without tracking
for partner in partners: for partner in partners:
# Discard 'To' with partner
if partner.email in email_to_list:
email_to_list.discard(partner.email)
# If there is partners not included, then status is 'unknown' # If there is partners not included, then status is 'unknown'
# and perhaps a Cc recipient # and perhaps a Cc recipient
isCc = False isCc = False
if partner.email in email_cc_list: if partner.email in email_cc_list:
email_cc_list.discard(partner.email) email_cc_list.discard(partner.email)
isCc = True isCc = True
tracking_unkown_values.update( tracking_status = tracking_unknown_values.copy()
tracking_status.update(
{"recipient": partner.name, "partner_id": partner.id, "isCc": isCc} {"recipient": partner.name, "partner_id": partner.id, "isCc": isCc}
) )
partner_trackings.append(tracking_unkown_values.copy()) partner_trackings.append(tracking_status)
for email in email_cc_list: # Process Cc/To recipients without partner
# If there is Cc without partner for cc, lst in [(True, email_cc_list), (False, email_to_list)]:
tracking_unkown_values.update( for email in lst:
{"recipient": email, "partner_id": False, "isCc": True} tracking_status = tracking_unknown_values.copy()
tracking_status.update(
{"recipient": email, "partner_id": False, "isCc": cc}
) )
partner_trackings.append(tracking_unkown_values.copy()) partner_trackings.append(tracking_status)
res[message.id] = { res[message.id] = {
"partner_trackings": partner_trackings, "partner_trackings": partner_trackings,
"is_failed_message": message.is_failed_message, "is_failed_message": message.is_failed_message,
} }
return res return res
@api.model
def _drop_aliases(self, mail_list):
aliases = self.env["mail.alias"].get_aliases()
def _filter_alias(email):
email_wn = getaddresses([email])[0][1]
if email_wn not in aliases:
return email_wn
return list(filter(_filter_alias, mail_list))
@api.model @api.model
def _message_read_dict_postprocess(self, messages, message_tree): def _message_read_dict_postprocess(self, messages, message_tree):
"""Preare values to be used by the chatter widget""" """Preare values to be used by the chatter widget"""

View File

@ -33,41 +33,48 @@ class MailThread(models.AbstractModel):
def message_post(self, *args, **kwargs): def message_post(self, *args, **kwargs):
"""Adds CC recipient to the message. """Adds CC recipient to the message.
Because Odoo implementation avoid store cc recipients we ensure that Because Odoo implementation avoid store 'from, to, cc' recipients we
this information its written into the mail.message record. ensure that this information its written into the mail.message record.
""" """
new_message = super().message_post(*args, **kwargs) kwargs.update(
email_cc = kwargs.get("cc") {"email_cc": kwargs.get("cc", False), "email_to": kwargs.get("to", False)}
if email_cc: )
new_message.sudo().write({"email_cc": email_cc}) return super().message_post(*args, **kwargs)
return new_message
def _message_get_suggested_recipients(self): def _message_get_suggested_recipients(self):
"""Adds email Cc recipients as suggested recipients. """Adds email 'extra' recipients as suggested recipients.
If the recipient has a res.partner, use it. If the recipient has a res.partner, use it.
""" """
res = super()._message_get_suggested_recipients() res = super()._message_get_suggested_recipients()
self._add_extra_recipients_suggestions(res, "email_cc", _("Cc"))
self._add_extra_recipients_suggestions(res, "email_to", _("Anon. To"))
return res
def _add_extra_recipients_suggestions(self, suggestions, field_mail, reason):
ResPartnerObj = self.env["res.partner"] ResPartnerObj = self.env["res.partner"]
email_cc_formated_list = [] aliases = self.env["mail.alias"].get_aliases()
email_extra_formated_list = []
for record in self: for record in self:
emails_cc = record.message_ids.mapped("email_cc") emails_extra = record.message_ids.mapped(field_mail)
for email in emails_cc: for email in emails_extra:
email_cc_formated_list.extend(email_split_and_format(email)) email_extra_formated_list.extend(email_split_and_format(email))
email_cc_formated_list = set(email_cc_formated_list) email_extra_formated_list = set(email_extra_formated_list)
for cc in email_cc_formated_list: email_extra_list = [x[1] for x in getaddresses(email_extra_formated_list)]
email_parts = getaddresses([cc])[0] partners_info = self._message_partner_info_from_emails(email_extra_list)
partner_id = record._message_partner_info_from_emails([email_parts[1]])[ for pinfo in partners_info:
0 partner_id = pinfo["partner_id"]
].get("partner_id") email = pinfo["full_name"]
if not partner_id: if not partner_id:
record._message_add_suggested_recipient(res, email=cc, reason=_("Cc")) if email not in aliases:
self._message_add_suggested_recipient(
suggestions, email=email, reason=reason
)
else: else:
partner = ResPartnerObj.browse(partner_id) partner = ResPartnerObj.browse(partner_id)
record._message_add_suggested_recipient( self._message_add_suggested_recipient(
res, partner=partner, reason=_("Cc") suggestions, partner=partner, reason=reason
) )
return res
@api.model @api.model
def _fields_view_get( def _fields_view_get(

View File

@ -28,6 +28,9 @@ These are all available status icons:
.. |noemail| image:: ../static/src/img/no_email.png .. |noemail| image:: ../static/src/img/no_email.png
:width: 10px :width: 10px
.. |anonuser| image:: ../static/src/img/anon_user.png
:width: 10px
|unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never' |unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never'
|waiting| **Waiting**: Waiting to be sent |waiting| **Waiting**: Waiting to be sent
@ -44,6 +47,8 @@ These are all available status icons:
|noemail| **No Email**: The partner doesn't have a defined email |noemail| **No Email**: The partner doesn't have a defined email
|anonuser| **No Partner**: The recipient doesn't have a defined partner
If you want to see all tracking emails and events you can go to If you want to see all tracking emails and events you can go to

View File

@ -412,6 +412,7 @@ status icon will appear just right to name of notified partner.</p>
<p><img alt="opened" src="https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/opened.png" style="width: 15px;" /> <strong>Opened</strong>: Opened by partner</p> <p><img alt="opened" src="https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/opened.png" style="width: 15px;" /> <strong>Opened</strong>: Opened by partner</p>
<p><img alt="cc" src="https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/cc.png" style="width: 10px;" /> <strong>Cc</strong>: Its a Carbon-Copy recipient. Cant know the status so is Unknown</p> <p><img alt="cc" src="https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/cc.png" style="width: 10px;" /> <strong>Cc</strong>: Its a Carbon-Copy recipient. Cant know the status so is Unknown</p>
<p><img alt="noemail" src="https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/no_email.png" style="width: 10px;" /> <strong>No Email</strong>: The partner doesnt have a defined email</p> <p><img alt="noemail" src="https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/no_email.png" style="width: 10px;" /> <strong>No Email</strong>: The partner doesnt have a defined email</p>
<p><img alt="anonuser" src="https://raw.githubusercontent.com/OCA/social/13.0/mail_tracking/static/src/img/anon_user.png" style="width: 10px;" /> <strong>No Partner</strong>: The recipient doesnt have a defined partner</p>
<p>If you want to see all tracking emails and events you can go to</p> <p>If you want to see all tracking emails and events you can go to</p>
<ul class="simple"> <ul class="simple">
<li>Settings &gt; Technical &gt; Email &gt; Tracking emails</li> <li>Settings &gt; Technical &gt; Email &gt; Tracking emails</li>

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

View File

@ -10,6 +10,11 @@
<i class="fa fa-cc"></i> <i class="fa fa-cc"></i>
</span> </span>
</t> </t>
<t t-elif="!tracking['isCc'] &amp;&amp; !tracking['partner_id']">
<span class="mail_anon_recipient">
<i class="fa fa-low-vision"></i>
</span>
</t>
<t t-elif="tracking['status'] === 'unknown'"> <t t-elif="tracking['status'] === 'unknown'">
<span class="mail_tracking_unknown"> <span class="mail_tracking_unknown">
<i class="fa fa-ban"></i> <i class="fa fa-ban"></i>

View File

@ -9,7 +9,7 @@ import psycopg2
import psycopg2.errorcodes import psycopg2.errorcodes
from lxml import etree from lxml import etree
from odoo import _, http from odoo import http
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
from odoo.tools import mute_logger from odoo.tools import mute_logger
@ -179,8 +179,9 @@ class TestMailTracking(TransactionCase):
"login": "sender-test", "login": "sender-test",
} }
) )
# pylint: disable=C8107
message = self.recipient.with_user(sender_user).message_post( message = self.recipient.with_user(sender_user).message_post(
body=_("<p>This is a test message</p>"), body="<p>This is a test message</p>",
cc="unnamed@test.com, sender@example.com", cc="unnamed@test.com, sender@example.com",
) )
# suggested recipients # suggested recipients