Browse Source

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.
pull/27/head
Jairo Llopis 6 years ago
committed by fkantelberg
parent
commit
79a449e021
  1. 1
      privacy_consent/__init__.py
  2. 4
      privacy_consent/models/mail_mail.py
  3. 5
      privacy_consent/models/privacy_activity.py
  4. 4
      privacy_consent/models/privacy_consent.py
  5. 1
      privacy_consent/wizards/__init__.py
  6. 16
      privacy_consent/wizards/mail_compose_message.py

1
privacy_consent/__init__.py

@ -1,3 +1,2 @@
from . import controllers from . import controllers
from . import models from . import models
from . import wizards

4
privacy_consent/models/mail_mail.py

@ -10,7 +10,7 @@ class MailMail(models.Model):
def _postprocess_sent_message(self, mail_sent=True): def _postprocess_sent_message(self, mail_sent=True):
"""Write consent status after sending message.""" """Write consent status after sending message."""
if mail_sent and self.env.context.get('mark_consent_sent'):
if mail_sent:
# Get all mails sent to consents # Get all mails sent to consents
consent_mails = self.filtered( consent_mails = self.filtered(
lambda one: one.mail_message_id.model == "privacy.consent" lambda one: one.mail_message_id.model == "privacy.consent"
@ -37,7 +37,7 @@ class MailMail(models.Model):
""" """
result = super(MailMail, self).send_get_mail_body(partner=partner) result = super(MailMail, self).send_get_mail_body(partner=partner)
# Avoid polluting other model mails # Avoid polluting other model mails
if self.env.context.get("active_model") != "privacy.consent":
if self.model != "privacy.consent":
return result return result
# Tokenize consent links # Tokenize consent links
consent = self.env["privacy.consent"] \ consent = self.env["privacy.consent"] \

5
privacy_consent/models/privacy_activity.py

@ -120,11 +120,10 @@ class PrivacyActivity(models.Model):
# Skip activitys where consent is not required # Skip activitys where consent is not required
for one in self.with_context(active_test=False) \ for one in self.with_context(active_test=False) \
.filtered("consent_required"): .filtered("consent_required"):
domain = safe_eval(one.subject_domain)
domain += [
domain = [
("id", "not in", one.mapped("consent_ids.partner_id").ids), ("id", "not in", one.mapped("consent_ids.partner_id").ids),
("email", "!=", False), ("email", "!=", False),
]
] + safe_eval(one.subject_domain)
# Create missing consent requests # Create missing consent requests
for missing in self.env["res.partner"].search(domain): for missing in self.env["res.partner"].search(domain):
consents |= consents.create({ consents |= consents.create({

4
privacy_consent/models/privacy_consent.py

@ -104,8 +104,7 @@ class PrivacyConsent(models.Model):
consents_by_template = {} consents_by_template = {}
for one in self.with_context(tpl_force_default_to=True, for one in self.with_context(tpl_force_default_to=True,
mail_notify_user_signature=False, mail_notify_user_signature=False,
mail_auto_subscribe_no_notify=True,
mark_consent_sent=True):
mail_auto_subscribe_no_notify=True):
# Group consents by template, to send in batch where possible # Group consents by template, to send in batch where possible
template_id = one.activity_id.consent_template_id.id template_id = one.activity_id.consent_template_id.id
consents_by_template.setdefault(template_id, one) consents_by_template.setdefault(template_id, one)
@ -168,7 +167,6 @@ class PrivacyConsent(models.Model):
"default_res_id": self.id, "default_res_id": self.id,
"default_template_id": self.activity_id.consent_template_id.id, "default_template_id": self.activity_id.consent_template_id.id,
"default_use_template": True, "default_use_template": True,
"mark_consent_sent": True,
"tpl_force_default_to": True, "tpl_force_default_to": True,
}, },
"force_email": True, "force_email": True,

1
privacy_consent/wizards/__init__.py

@ -1 +0,0 @@
from . import mail_compose_message

16
privacy_consent/wizards/mail_compose_message.py

@ -1,16 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Tecnativa - Jairo Llopis
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, models
class MailComposeMessage(models.TransientModel):
_inherit = "mail.compose.message"
@api.multi
def send_mail(self, auto_commit=False):
"""Force auto commit when sending consent emails."""
if self.env.context.get('mark_consent_sent'):
auto_commit = True
return super(MailComposeMessage, self).send_mail(auto_commit)
Loading…
Cancel
Save