# Copyright 2016 Antonio Espinosa - # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import re import time from datetime import datetime from odoo import api, fields, models class MailTrackingEvent(models.Model): _name = "mail.tracking.event" _order = "timestamp desc" _rec_name = "event_type" _description = "MailTracking event" recipient = fields.Char(readonly=True) recipient_address = fields.Char( string="Recipient email address", readonly=True, store=True, compute="_compute_recipient_address", index=True, ) timestamp = fields.Float( string="UTC timestamp", readonly=True, digits="MailTracking Timestamp" ) time = fields.Datetime(readonly=True) date = fields.Date(readonly=True, compute="_compute_date", store=True) tracking_email_id = fields.Many2one( string="Message", readonly=True, required=True, ondelete="cascade", comodel_name="mail.tracking.email", index=True, ) event_type = fields.Selection( selection=[ ("sent", "Sent"), ("delivered", "Delivered"), ("deferral", "Deferral"), ("hard_bounce", "Hard bounce"), ("soft_bounce", "Soft bounce"), ("open", "Open"), ("click", "Clicked"), ("spam", "Spam"), ("unsub", "Unsubscribed"), ("reject", "Rejected"), ], readonly=True, ) smtp_server = fields.Char(string="SMTP server", readonly=True) url = fields.Char(string="Clicked URL", readonly=True) ip = fields.Char(string="User IP", readonly=True) user_agent = fields.Char(readonly=True) mobile = fields.Boolean(string="Is mobile?", readonly=True) os_family = fields.Char(string="Operating system family", readonly=True) ua_family = fields.Char(string="User agent family", readonly=True) ua_type = fields.Char(string="User agent type", readonly=True) user_country_id = fields.Many2one( string="User country", readonly=True, comodel_name="res.country" ) error_type = fields.Char(readonly=True) error_description = fields.Char(readonly=True) error_details = fields.Text(readonly=True) @api.depends("recipient") def _compute_recipient_address(self): for email in self: if email.recipient: matches = re.search(r"<(.*@.*)>", email.recipient) if matches: email.recipient_address = matches.group(1).lower() else: email.recipient_address = email.recipient.lower() else: email.recipient_address = False @api.depends("time") def _compute_date(self): for email in self: email.date = fields.Date.to_string(fields.Date.from_string(email.time)) def _process_data(self, tracking_email, metadata, event_type, state): ts = time.time() dt = datetime.utcfromtimestamp(ts) return { "recipient": metadata.get("recipient", tracking_email.recipient), "timestamp": metadata.get("timestamp", ts), "time": metadata.get("time", fields.Datetime.to_string(dt)), "date": metadata.get("date", fields.Date.to_string(dt)), "tracking_email_id": tracking_email.id, "event_type": event_type, "ip": metadata.get("ip", False), "url": metadata.get("url", False), "user_agent": metadata.get("user_agent", False), "mobile": metadata.get("mobile", False), "os_family": metadata.get("os_family", False), "ua_family": metadata.get("ua_family", False), "ua_type": metadata.get("ua_type", False), "user_country_id": metadata.get("user_country_id", False), "error_type": metadata.get("error_type", False), "error_description": metadata.get("error_description", False), "error_details": metadata.get("error_details", False), } def _process_status(self, tracking_email, metadata, event_type, state): tracking_email.sudo().write({"state": state}) return self._process_data(tracking_email, metadata, event_type, state) def _process_bounce(self, tracking_email, metadata, event_type, state): tracking_email.sudo().write( { "state": state, "bounce_type": metadata.get("bounce_type", False), "bounce_description": metadata.get("bounce_description", False), } ) return self._process_data(tracking_email, metadata, event_type, state) @api.model def process_delivered(self, tracking_email, metadata): return self._process_status(tracking_email, metadata, "delivered", "delivered") @api.model def process_deferral(self, tracking_email, metadata): return self._process_status(tracking_email, metadata, "deferral", "deferred") @api.model def process_hard_bounce(self, tracking_email, metadata): return self._process_bounce(tracking_email, metadata, "hard_bounce", "bounced") @api.model def process_soft_bounce(self, tracking_email, metadata): return self._process_bounce( tracking_email, metadata, "soft_bounce", "soft-bounced" ) @api.model def process_open(self, tracking_email, metadata): return self._process_status(tracking_email, metadata, "open", "opened") @api.model def process_click(self, tracking_email, metadata): return self._process_status(tracking_email, metadata, "click", "opened") @api.model def process_spam(self, tracking_email, metadata): return self._process_status(tracking_email, metadata, "spam", "spam") @api.model def process_unsub(self, tracking_email, metadata): return self._process_status(tracking_email, metadata, "unsub", "unsub") @api.model def process_reject(self, tracking_email, metadata): return self._process_status(tracking_email, metadata, "reject", "rejected")