privacy_consent: Avoid race condition with mail queue cron
Before this patch, all privacy consent emails were forced to be sent under a context with `mark_consent_sent=True` to track the state change and trigger the attached server action.
When using the automatic mode, if a separate cron job started running the mail queue, it could happen that mails were being sent from that another worker, losing the context key and, as such, being sent without token and without being marked as sent nor executing the attached server action (if any).
To avoid this problem, now the context dependency is removed. After all, the `mail.mail` object is only created when sending in `mass_mail` model, so other kind of notifications or messages are not affected. When a mail of type `mass_mail` is sent, we can assume that it is asking for consent and we can move draft consent requests to sent.
6 years ago |
|
# Copyright 2018 Tecnativa - Jairo Llopis # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import models
class MailMail(models.Model): _inherit = "mail.mail"
def _postprocess_sent_message(self, success_pids, failure_reason=False, failure_type=None): """Write consent status after sending message.""" # Know if mail was successfully sent to a privacy consent if ( self.mail_message_id.model == "privacy.consent" and self.state == "sent" and success_pids and not failure_reason and not failure_type ): # Get related consent consent = self.env["privacy.consent"].browse( self.mail_message_id.res_id, self._prefetch, ) # Set as sent if needed if ( consent.state == "draft" and consent.partner_id.id in {par.id for par in success_pids} ): consent.write({ "state": "sent", }) return super()._postprocess_sent_message( success_pids=success_pids, failure_reason=failure_reason, failure_type=failure_type, )
def _send_prepare_body(self): """Replace privacy consent magic links.
This replacement is done here instead of directly writing it into the ``mail.template`` to avoid writing the tokeinzed URL in the mail thread for the ``privacy.consent`` record, which would enable any reader of such thread to impersonate the subject and choose in its behalf. """
result = super(MailMail, self)._send_prepare_body() # Avoid polluting other model mails if self.model != "privacy.consent": return result # Tokenize consent links consent = self.env["privacy.consent"] \ .browse(self.mail_message_id.res_id) \ .with_prefetch(self._prefetch) result = result.replace( "/privacy/consent/accept/", consent._url(True), ) result = result.replace( "/privacy/consent/reject/", consent._url(False), ) return result
|