diff --git a/superset/views/base_api.py b/superset/views/base_api.py index 976f5b499e8..de5d9280420 100644 --- a/superset/views/base_api.py +++ b/superset/views/base_api.py @@ -93,6 +93,18 @@ class BaseSupersetModelRestApi(ModelRestApi): } """ # pylint: disable=pointless-string-statement + def _init_properties(self): + model_id = self.datamodel.get_pk_name() + if self.list_columns is None and not self.list_model_schema: + self.list_columns = [model_id] + if self.show_columns is None and not self.show_model_schema: + self.show_columns = [model_id] + if self.edit_columns is None and not self.edit_model_schema: + self.edit_columns = [model_id] + if self.add_columns is None and not self.add_model_schema: + self.add_columns = [model_id] + super()._init_properties() + def _get_related_filter(self, datamodel, column_name: str, value: str) -> Filters: filter_field = self.filter_rel_fields_field.get(column_name) filters = datamodel.get_filters([filter_field]) diff --git a/tests/base_api_tests.py b/tests/base_api_tests.py index c9e53d4d767..5364b53d2f1 100644 --- a/tests/base_api_tests.py +++ b/tests/base_api_tests.py @@ -17,9 +17,114 @@ # isort:skip_file import json +from flask_appbuilder.models.sqla.interface import SQLAInterface import prison from superset import db, security_manager +from superset.extensions import appbuilder +from superset.models.dashboard import Dashboard +from superset.views.base_api import BaseSupersetModelRestApi + +from .base_tests import SupersetTestCase + + +class Model1Api(BaseSupersetModelRestApi): + datamodel = SQLAInterface(Dashboard) + class_permission_name = "DashboardModelView" + method_permission_name = { + "get_list": "list", + "get": "show", + "export": "mulexport", + "post": "add", + "put": "edit", + "delete": "delete", + "bulk_delete": "delete", + "info": "list", + "related": "list", + } + + +appbuilder.add_api(Model1Api) + + +class BaseModelRestApiTests(SupersetTestCase): + def test_default_missing_declaration_get(self): + """ + API: Test default missing declaration on get + """ + # Check get list response + self.login(username="admin") + uri = "api/v1/model1api/" + rv = self.client.get(uri) + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(response["list_columns"], ["id"]) + for result in response["result"]: + self.assertEqual(list(result.keys()), ["id"]) + + # Check get response + dashboard = db.session.query(Dashboard).first() + uri = f"api/v1/model1api/{dashboard.id}" + rv = self.client.get(uri) + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(response["show_columns"], ["id"]) + self.assertEqual(list(response["result"].keys()), ["id"]) + + def test_default_missing_declaration_put_spec(self): + self.login(username="admin") + uri = "api/v1/_openapi" + rv = self.client.get(uri) + # dashboard model accepts all fields are null + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + expected_mutation_spec = { + "properties": {"id": {"format": "int32", "type": "integer"}}, + "type": "object", + } + self.assertEqual( + response["components"]["schemas"]["Model1Api.post"], expected_mutation_spec + ) + self.assertEqual( + response["components"]["schemas"]["Model1Api.put"], expected_mutation_spec + ) + + def test_default_missing_declaration_post(self): + dashboard_data = { + "dashboard_title": "title1", + "slug": "slug1", + "position_json": '{"a": "A"}', + "css": "css", + "json_metadata": '{"b": "B"}', + "published": True, + } + self.login(username="admin") + uri = "api/v1/model1api/" + rv = self.client.post(uri, json=dashboard_data) + # dashboard model accepts all fields are null + self.assertEqual(rv.status_code, 201) + response = json.loads(rv.data.decode("utf-8")) + self.assertEqual(list(response["result"].keys()), ["id"]) + model = db.session.query(Dashboard).get(response["id"]) + self.assertEqual(model.dashboard_title, None) + self.assertEqual(model.slug, None) + self.assertEqual(model.position_json, None) + self.assertEqual(model.json_metadata, None) + db.session.delete(model) + db.session.commit() + + def test_default_missing_declaration_put(self): + dashboard = db.session.query(Dashboard).first() + dashboard_data = {"dashboard_title": "CHANGED", "slug": "CHANGED"} + self.login(username="admin") + uri = f"api/v1/model1api/{dashboard.id}" + rv = self.client.put(uri, json=dashboard_data) + # dashboard model accepts all fields are null + self.assertEqual(rv.status_code, 200) + response = json.loads(rv.data.decode("utf-8")) + changed_dashboard = db.session.query(Dashboard).get(dashboard.id) + self.assertNotEqual(changed_dashboard.dashboard_title, "CHANGED") + self.assertNotEqual(changed_dashboard.slug, "CHANGED") class ApiOwnersTestCaseMixin: diff --git a/tests/dashboard_api_tests.py b/tests/dashboard_api_tests.py index 5b48bb852a3..2f72b2ea9af 100644 --- a/tests/dashboard_api_tests.py +++ b/tests/dashboard_api_tests.py @@ -282,7 +282,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): "published": True, } self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 201) data = json.loads(rv.data.decode("utf-8")) @@ -296,7 +296,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): """ dashboard_data = {"dashboard_title": "title1"} self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 201) data = json.loads(rv.data.decode("utf-8")) @@ -310,7 +310,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): """ dashboard_data = {} self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 201) data = json.loads(rv.data.decode("utf-8")) @@ -320,7 +320,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): dashboard_data = {"dashboard_title": ""} self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 201) data = json.loads(rv.data.decode("utf-8")) @@ -334,7 +334,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): """ dashboard_data = {"dashboard_title": "a" * 600} self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 422) response = json.loads(rv.data.decode("utf-8")) @@ -353,7 +353,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): # Check for slug uniqueness dashboard_data = {"dashboard_title": "title2", "slug": "slug1"} - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 422) response = json.loads(rv.data.decode("utf-8")) @@ -362,7 +362,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): # Check for slug max size dashboard_data = {"dashboard_title": "title2", "slug": "a" * 256} - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 422) response = json.loads(rv.data.decode("utf-8")) @@ -378,7 +378,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): """ dashboard_data = {"dashboard_title": "title1", "owners": [1000]} self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 422) response = json.loads(rv.data.decode("utf-8")) @@ -391,13 +391,13 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): """ dashboard_data = {"dashboard_title": "title1", "position_json": '{"A:"a"}'} self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 422) dashboard_data = {"dashboard_title": "title1", "json_metadata": '{"A:"a"}'} self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 422) @@ -406,7 +406,7 @@ class DashboardApiTests(SupersetTestCase, ApiOwnersTestCaseMixin): "json_metadata": '{"refresh_frequency": "A"}', } self.login(username="admin") - uri = f"api/v1/dashboard/" + uri = "api/v1/dashboard/" rv = self.client.post(uri, json=dashboard_data) self.assertEqual(rv.status_code, 422)