mirror of
https://github.com/apache/superset.git
synced 2026-07-11 17:25:31 +00:00
fix(reports): stamp email subject date at send time, not import time (#40693)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -28,8 +28,8 @@ from pytz import timezone
|
||||
|
||||
from superset import is_feature_enabled
|
||||
from superset.exceptions import SupersetErrorsException
|
||||
from superset.reports.models import ReportRecipientType
|
||||
from superset.reports.notifications.base import BaseNotification
|
||||
from superset.reports.models import ReportRecipients, ReportRecipientType
|
||||
from superset.reports.notifications.base import BaseNotification, NotificationContent
|
||||
from superset.reports.notifications.exceptions import NotificationError
|
||||
from superset.utils import json
|
||||
from superset.utils.core import HeaderDataType, send_email_smtp
|
||||
@@ -83,7 +83,17 @@ class EmailNotification(BaseNotification): # pylint: disable=too-few-public-met
|
||||
"""
|
||||
|
||||
type = ReportRecipientType.EMAIL
|
||||
now = datetime.now(timezone("UTC"))
|
||||
|
||||
def __init__(
|
||||
self, recipient: ReportRecipients, content: NotificationContent
|
||||
) -> None:
|
||||
super().__init__(recipient, content)
|
||||
# Stamp each notification with its own timestamp at construction, which
|
||||
# happens per recipient immediately before the email is dispatched. The
|
||||
# date rendered into the subject (when DATE_FORMAT_IN_EMAIL_SUBJECT is
|
||||
# enabled) therefore tracks the dispatch time. A module- or class-level
|
||||
# value would instead freeze on the first import in a long-running worker.
|
||||
self.now = datetime.now(timezone("UTC"))
|
||||
|
||||
@property
|
||||
def _name(self) -> str:
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pandas as pd
|
||||
from freezegun import freeze_time
|
||||
from pytz import timezone
|
||||
|
||||
from tests.unit_tests.conftest import with_feature_flags
|
||||
@@ -107,8 +108,6 @@ def test_email_subject_with_datetime() -> None:
|
||||
from superset.reports.notifications.base import NotificationContent
|
||||
from superset.reports.notifications.email import EmailNotification
|
||||
|
||||
now = datetime.now(timezone("UTC"))
|
||||
|
||||
datetime_pattern = "%Y-%m-%d"
|
||||
|
||||
content = NotificationContent(
|
||||
@@ -130,8 +129,18 @@ def test_email_subject_with_datetime() -> None:
|
||||
"execution_id": "test-execution-id",
|
||||
},
|
||||
)
|
||||
subject = EmailNotification(
|
||||
recipient=ReportRecipients(type=ReportRecipientType.EMAIL), content=content
|
||||
)._get_subject()
|
||||
# Freeze the clock to a fixed, distinctive instant and construct the
|
||||
# notification *under* the freeze. The subject date must reflect this
|
||||
# frozen moment, which is only possible if the timestamp is stamped per
|
||||
# instance at construction/send time. If the timestamp were a class
|
||||
# attribute evaluated at import time (the regression this fixes), it would
|
||||
# carry the real import-time date instead and this assertion would fail.
|
||||
frozen_now = datetime(2021, 4, 22, 12, 0, 0, tzinfo=timezone("UTC"))
|
||||
with freeze_time(frozen_now):
|
||||
notification = EmailNotification(
|
||||
recipient=ReportRecipients(type=ReportRecipientType.EMAIL),
|
||||
content=content,
|
||||
)
|
||||
subject = notification._get_subject()
|
||||
assert datetime_pattern not in subject
|
||||
assert now.strftime(datetime_pattern) in subject
|
||||
assert frozen_now.strftime(datetime_pattern) in subject
|
||||
|
||||
Reference in New Issue
Block a user