diff --git a/superset/commands/report/execute.py b/superset/commands/report/execute.py index eadf193bf4ec0..afc488df5640f 100644 --- a/superset/commands/report/execute.py +++ b/superset/commands/report/execute.py @@ -426,6 +426,7 @@ def _get_notification_content(self) -> NotificationContent: name=self._report_schedule.name, text=error_text, header_data=header_data, + url=url, ) if ( @@ -533,13 +534,14 @@ def send_error(self, name: str, message: str) -> None: :raises: CommandException """ header_data = self._get_log_data() + url = self._get_url(user_friendly=True) logger.info( "header_data in notifications for alerts and reports %s, taskid, %s", header_data, self._execution_id, ) notification_content = NotificationContent( - name=name, text=message, header_data=header_data + name=name, text=message, header_data=header_data, url=url ) # filter recipients to recipients who are also owners diff --git a/superset/reports/notifications/email.py b/superset/reports/notifications/email.py index f5943f53927da..64aa6fe21150f 100644 --- a/superset/reports/notifications/email.py +++ b/superset/reports/notifications/email.py @@ -84,13 +84,16 @@ class EmailNotification(BaseNotification): # pylint: disable=too-few-public-met def _get_smtp_domain() -> str: return parseaddr(app.config["SMTP_MAIL_FROM"])[1].split("@")[1] - @staticmethod - def _error_template(text: str) -> str: + def _error_template(self, text: str) -> str: + call_to_action = self._get_call_to_action() return __( """ Error: %(text)s +

%(call_to_action)s

""", text=text, + url=self._content.url, + call_to_action=call_to_action, ) def _get_content(self) -> EmailContent: @@ -130,7 +133,6 @@ def _get_content(self) -> EmailContent: else: html_table = "" - call_to_action = __(app.config["EMAIL_REPORTS_CTA"]) img_tags = [] for msgid in images.keys(): img_tags.append( @@ -140,6 +142,7 @@ def _get_content(self) -> EmailContent: """ ) img_tag = "".join(img_tags) + call_to_action = self._get_call_to_action() body = textwrap.dedent( f""" @@ -190,6 +193,9 @@ def _get_subject(self) -> str: title=self._content.name, ) + def _get_call_to_action(self) -> str: + return __(app.config["EMAIL_REPORTS_CTA"]) + def _get_to(self) -> str: return json.loads(self._recipient.recipient_config_json)["target"] diff --git a/tests/integration_tests/reports/commands_tests.py b/tests/integration_tests/reports/commands_tests.py index 575c8a02b9d46..b5f37d571f98c 100644 --- a/tests/integration_tests/reports/commands_tests.py +++ b/tests/integration_tests/reports/commands_tests.py @@ -1767,6 +1767,11 @@ def test_email_dashboard_report_fails_uncaught_exception( ).run() assert_log(ReportState.ERROR, error_message="Uncaught exception") + assert ( + 'Explore in Superset' in email_mock.call_args[0][2] + ) @pytest.mark.usefixtures(