diff --git a/superset/commands/report/update.py b/superset/commands/report/update.py index 3bf51ee8f36..1ee09ea7a71 100644 --- a/superset/commands/report/update.py +++ b/superset/commands/report/update.py @@ -100,23 +100,19 @@ class UpdateReportScheduleCommand(UpdateMixin, BaseReportScheduleCommand): ) ) + # Determine effective database state (payload overrides model) + if "database" in self._properties: + has_database = self._properties["database"] is not None + else: + has_database = self._model.database_id is not None + # Validate database is not allowed on Report type - if report_type == ReportScheduleType.REPORT: - if "database" in self._properties: - has_database = self._properties["database"] is not None - else: - has_database = self._model.database_id is not None - if has_database: - exceptions.append(ReportScheduleDatabaseNotAllowedValidationError()) + if report_type == ReportScheduleType.REPORT and has_database: + exceptions.append(ReportScheduleDatabaseNotAllowedValidationError()) # Validate Alert has a database - if report_type == ReportScheduleType.ALERT: - if "database" in self._properties: - has_database = self._properties["database"] is not None - else: - has_database = self._model.database_id is not None - if not has_database: - exceptions.append(ReportScheduleAlertRequiredDatabaseValidationError()) + if report_type == ReportScheduleType.ALERT and not has_database: + exceptions.append(ReportScheduleAlertRequiredDatabaseValidationError()) # Validate if DB exists (for alerts) if report_type == ReportScheduleType.ALERT and database_id is not None: diff --git a/tests/integration_tests/reports/api_tests.py b/tests/integration_tests/reports/api_tests.py index 48ccb6f18ad..87fb8ccf046 100644 --- a/tests/integration_tests/reports/api_tests.py +++ b/tests/integration_tests/reports/api_tests.py @@ -1654,6 +1654,38 @@ class TestReportSchedulesApi(SupersetTestCase): "message": {"database": "Database reference is not allowed on a report"} } + @pytest.mark.usefixtures("create_report_schedules") + def test_update_report_schedule_nonexistent_database_returns_not_allowed(self): + """ + ReportSchedule API: Test Report + nonexistent DB returns 'not allowed', + not 'does not exist' — type invariant takes precedence. + """ + self.login(ADMIN_USERNAME) + + report_schedule = ( + db.session.query(ReportSchedule) + .filter(ReportSchedule.name == "name1") + .one_or_none() + ) + uri = f"api/v1/report/{report_schedule.id}" + + # Transition to Report type first + rv = self.put_assert_metric( + uri, + {"type": ReportScheduleType.REPORT, "database": None}, + "put", + ) + assert rv.status_code == 200 + + # Report + nonexistent DB → 422 "not allowed" (not "does not exist") + database_max_id = db.session.query(func.max(Database.id)).scalar() + rv = self.put_assert_metric(uri, {"database": database_max_id + 1}, "put") + assert rv.status_code == 422 + data = json.loads(rv.data.decode("utf-8")) + assert data == { + "message": {"database": "Database reference is not allowed on a report"} + } + @pytest.mark.usefixtures("create_report_schedules") def test_update_alert_schedule_database_allowed(self): """