diff --git a/mail_chatter_statistics/__init__.py b/mail_chatter_statistics/__init__.py new file mode 100644 index 0000000000..91c5580fed --- /dev/null +++ b/mail_chatter_statistics/__init__.py @@ -0,0 +1,2 @@ +from . import controllers +from . import models diff --git a/mail_chatter_statistics/__manifest__.py b/mail_chatter_statistics/__manifest__.py new file mode 100644 index 0000000000..7bd34f63b4 --- /dev/null +++ b/mail_chatter_statistics/__manifest__.py @@ -0,0 +1,15 @@ +{ + "name": "Mail Chatter Statistics", + "version": "14.0.1.0.0", + "author": "Avanzosc", + "summary": "Add email tracking functionality to Odoo chatter.", + "website": "https://github.com/avanzosc/odoo-addons", + "license": "LGPL-3", + "depends": ["mail", "mass_mailing"], + "data": [ + "views/mail_mail_views.xml", + "views/mailing_trace_views.xml", + ], + "installable": True, + "application": False, +} diff --git a/mail_chatter_statistics/controllers/__init__.py b/mail_chatter_statistics/controllers/__init__.py new file mode 100644 index 0000000000..352326ebe3 --- /dev/null +++ b/mail_chatter_statistics/controllers/__init__.py @@ -0,0 +1 @@ +from . import mail_track diff --git a/mail_chatter_statistics/controllers/mail_track.py b/mail_chatter_statistics/controllers/mail_track.py new file mode 100644 index 0000000000..ecc3b6ffd4 --- /dev/null +++ b/mail_chatter_statistics/controllers/mail_track.py @@ -0,0 +1,16 @@ +from odoo.http import Controller, request, route + + +class MailTrackController(Controller): + @route("/mail/track/click/", type="http", auth="public", website=True) + def track_click(self, trace_id, redirect_url=None, **kwargs): + """ + Logs the click event and redirects the user to the original URL + """ + trace = request.env["mailing.trace"].sudo().browse(trace_id) + if trace: + trace.write({"status": "clicked"}) + + if redirect_url: + return request.redirect(redirect_url) + return request.redirect("/") diff --git a/mail_chatter_statistics/models/__init__.py b/mail_chatter_statistics/models/__init__.py new file mode 100644 index 0000000000..afafc5b6d9 --- /dev/null +++ b/mail_chatter_statistics/models/__init__.py @@ -0,0 +1,2 @@ +from . import mail_mail +from . import mailing_trace diff --git a/mail_chatter_statistics/models/mail_mail.py b/mail_chatter_statistics/models/mail_mail.py new file mode 100644 index 0000000000..75f4e5ba64 --- /dev/null +++ b/mail_chatter_statistics/models/mail_mail.py @@ -0,0 +1,52 @@ +from bs4 import BeautifulSoup + +from odoo import models, tools + + +class MailMail(models.Model): + _inherit = "mail.mail" + + def send(self, auto_commit=False, raise_exception=False): + res = super().send(auto_commit=auto_commit, raise_exception=raise_exception) + + for mail in self: + trace = self.env["mailing.trace"].create( + { + "mail_id": mail.id, + "email": mail.email_to, + "status": "sent", + "message_id": mail.message_id, + } + ) + mail.body_html = self._add_tracking(mail.body_html, trace.id) + trace.write({"status": "tracking_added"}) + + return res + + def _add_tracking(self, body_html, trace_id): + """ + Add tracking pixel and replace links for click tracking + """ + tracking_pixel = f'' + body_html = body_html.replace("", f"{tracking_pixel}") + + body_html = self._replace_links_with_tracked(body_html, trace_id) + + return body_html + + def _replace_links_with_tracked(self, body_html, trace_id): + """ + Replace all the hyperlinks in the email with tracked versions + """ + soup = BeautifulSoup(body_html, "html.parser") + + for a_tag in soup.find_all("a", href=True): + original_url = a_tag["href"] + + tracked_url = f"/mail/track/click/{trace_id}?\ + redirect_url={tools.url_quote(original_url)}" + + a_tag["href"] = tracked_url + + return str(soup) diff --git a/mail_chatter_statistics/models/mailing_trace.py b/mail_chatter_statistics/models/mailing_trace.py new file mode 100644 index 0000000000..54cad4c643 --- /dev/null +++ b/mail_chatter_statistics/models/mailing_trace.py @@ -0,0 +1,19 @@ +from odoo import fields, models + + +class MailingTrace(models.Model): + _inherit = "mailing.trace" + + mail_message_id = fields.Many2one( + "mail.message", + string="Chatter Message", + help="The chatter message related to this email trace.", + ) + + mail_message_id_int = fields.Integer( + string="Message ID (tech)", + help="ID of the related mail_message. This field is an integer field because " + "the related mail_message can be deleted separately from its statistics. " + "However the ID is needed for several action and controllers.", + index=True, + ) \ No newline at end of file diff --git a/mail_chatter_statistics/views/mail_mail_views.xml b/mail_chatter_statistics/views/mail_mail_views.xml new file mode 100644 index 0000000000..dcffa9f7d6 --- /dev/null +++ b/mail_chatter_statistics/views/mail_mail_views.xml @@ -0,0 +1,18 @@ + + + + mail.mail.form.view.stats + mail.mail + + + +