diff --git a/superset/dashboards/commands/update.py b/superset/dashboards/commands/update.py index 27cd13dd4..f32483593 100644 --- a/superset/dashboards/commands/update.py +++ b/superset/dashboards/commands/update.py @@ -57,7 +57,7 @@ class UpdateDashboardCommand(BaseCommand): def validate(self) -> None: exceptions: List[ValidationError] = [] owner_ids: Optional[List[int]] = self._properties.get("owners") - slug: str = self._properties.get("slug", "") + slug: Optional[str] = self._properties.get("slug") # Validate/populate model exists self._model = DashboardDAO.find_by_id(self._model_id) diff --git a/superset/dashboards/dao.py b/superset/dashboards/dao.py index 86684bbbd..923a9c913 100644 --- a/superset/dashboards/dao.py +++ b/superset/dashboards/dao.py @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. import logging -from typing import List +from typing import List, Optional from sqlalchemy.exc import SQLAlchemyError @@ -39,11 +39,13 @@ class DashboardDAO(BaseDAO): return not db.session.query(dashboard_query.exists()).scalar() @staticmethod - def validate_update_slug_uniqueness(dashboard_id: int, slug: str) -> bool: - dashboard_query = db.session.query(Dashboard).filter( - Dashboard.slug == slug, Dashboard.id != dashboard_id - ) - return not db.session.query(dashboard_query.exists()).scalar() + def validate_update_slug_uniqueness(dashboard_id: int, slug: Optional[str]) -> bool: + if slug is not None: + dashboard_query = db.session.query(Dashboard).filter( + Dashboard.slug == slug, Dashboard.id != dashboard_id + ) + return not db.session.query(dashboard_query.exists()).scalar() + return True @staticmethod def bulk_delete(models: List[Dashboard], commit=True): diff --git a/tests/dashboards/api_tests.py b/tests/dashboards/api_tests.py index e00adcb44..45b588f04 100644 --- a/tests/dashboards/api_tests.py +++ b/tests/dashboards/api_tests.py @@ -50,7 +50,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): def insert_dashboard( self, dashboard_title: str, - slug: str, + slug: Optional[str], owners: List[int], slices: Optional[List[Slice]] = None, position_json: str = "", @@ -647,6 +647,19 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): db.session.delete(dashboard2) db.session.commit() + dashboard1 = self.insert_dashboard("title1", None, [admin_id]) + dashboard2 = self.insert_dashboard("title2", None, [admin_id]) + self.login(username="admin") + # Accept empty slugs and don't validate them has unique + dashboard_data = {"dashboard_title": "title2_changed", "slug": ""} + uri = f"api/v1/dashboard/{dashboard2.id}" + rv = self.client.put(uri, json=dashboard_data) + self.assertEqual(rv.status_code, 200) + + db.session.delete(dashboard1) + db.session.delete(dashboard2) + db.session.commit() + def test_update_published(self): """ Dashboard API: Test update published patch