You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by va...@apache.org on 2025/03/17 16:16:18 UTC
(superset) branch feat/list-only-allowed-schemas-for-upload created (now e2559552b1)
This is an automated email from the ASF dual-hosted git repository.
vavila pushed a change to branch feat/list-only-allowed-schemas-for-upload
in repository https://gitbox.apache.org/repos/asf/superset.git
at e2559552b1 feat(file uploads): List only allowed schemas in the file uploads dialog
This branch includes the following new commits:
new e2559552b1 feat(file uploads): List only allowed schemas in the file uploads dialog
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(superset) 01/01: feat(file uploads): List only allowed schemas in the file uploads dialog
Posted by va...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
vavila pushed a commit to branch feat/list-only-allowed-schemas-for-upload
in repository https://gitbox.apache.org/repos/asf/superset.git
commit e2559552b185bc056e10afda7357e841f86dfe8b
Author: Vitor Avila <vi...@preset.io>
AuthorDate: Mon Mar 17 13:15:59 2025 -0300
feat(file uploads): List only allowed schemas in the file uploads dialog
---
superset/databases/api.py | 24 +++++++++-
superset/databases/schemas.py | 1 +
tests/integration_tests/databases/api_tests.py | 64 ++++++++++++++++++++++++++
3 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/superset/databases/api.py b/superset/databases/api.py
index 5c3e024e73..a573823fc5 100644
--- a/superset/databases/api.py
+++ b/superset/databases/api.py
@@ -776,18 +776,38 @@ class DatabaseRestApi(BaseSupersetModelRestApi):
if not database:
return self.response_404()
try:
- catalog = kwargs["rison"].get("catalog")
+ params = kwargs["rison"]
+ catalog = params.get("catalog")
schemas = database.get_all_schema_names(
catalog=catalog,
cache=database.schema_cache_enabled,
cache_timeout=database.schema_cache_timeout or None,
- force=kwargs["rison"].get("force", False),
+ force=params.get("force", False),
)
schemas = security_manager.get_schemas_accessible_by_user(
database,
catalog,
schemas,
)
+ if params.get("upload_allowed"):
+ if not database.allow_file_upload:
+ return self.response(
+ 400,
+ message="File upload is disabled on this database connection",
+ )
+ if allowed_schemas := database.get_schema_access_for_file_upload():
+ # some databases might return the list of schemas in uppercase,
+ # while the list of allowed schemas is manually inputted so
+ # could be lowercase
+ allowed_schemas = {schema.lower() for schema in allowed_schemas}
+ return self.response(
+ 200,
+ result=[
+ schema
+ for schema in schemas
+ if schema.lower() in allowed_schemas
+ ],
+ )
return self.response(200, result=list(schemas))
except OperationalError:
return self.response(
diff --git a/superset/databases/schemas.py b/superset/databases/schemas.py
index c9df9fcbad..765f9dde83 100644
--- a/superset/databases/schemas.py
+++ b/superset/databases/schemas.py
@@ -64,6 +64,7 @@ database_schemas_query_schema = {
"type": "object",
"properties": {
"force": {"type": "boolean"},
+ "upload_allowed": {"type": "boolean"},
"catalog": {"type": "string"},
},
}
diff --git a/tests/integration_tests/databases/api_tests.py b/tests/integration_tests/databases/api_tests.py
index 76e76dca18..d9081d72b1 100644
--- a/tests/integration_tests/databases/api_tests.py
+++ b/tests/integration_tests/databases/api_tests.py
@@ -2083,6 +2083,70 @@ class TestDatabaseApi(SupersetTestCase):
)
assert rv.status_code == 400
+ @pytest.mark.parametrize(
+ "all_schemas,schemas_allowed_for_csv,result",
+ [
+ (
+ ["schema_1", "schema_2", "schema_3"],
+ [],
+ ["schema_1", "schema_2", "schema_3"],
+ ),
+ (["schema_1", "schema_2", "schema_3"], ["schema_2"], ["schema_2"]),
+ ],
+ )
+ def test_database_schemas_upload_allowed_filter(
+ self,
+ all_schemas: list[str],
+ schemas_allowed_for_csv: list[str],
+ result: list[str],
+ ):
+ """
+ Database API: Test database schemas when filtering for upload allowed
+ """
+ with self.create_app().app_context():
+ example_db = get_example_database()
+
+ extra = {
+ "metadata_params": {},
+ "engine_params": {},
+ "metadata_cache_timeout": {},
+ "schemas_allowed_for_file_upload": schemas_allowed_for_csv,
+ }
+ self.login(ADMIN_USERNAME)
+ database = self.insert_database(
+ "database_with_upload",
+ example_db.sqlalchemy_uri_decrypted,
+ extra=json.dumps(extra),
+ allow_file_upload=True,
+ )
+ db.session.commit()
+ yield database
+
+ mock.patch.object(
+ database, "get_all_schema_names", return_value=all_schemas
+ )
+ arguments = {"upload_allowed": True}
+ uri = f"api/v1/database/{database.id}/schemas/?q={prison.dumps(arguments)}"
+ rv = self.client.get(uri)
+ data = json.loads(rv.data.decode("utf-8"))
+ assert data["result"] == result
+ db.session.delete(database)
+ db.session.commit()
+
+ def test_database_schemas_upload_allowed_filter_disabled(self):
+ """
+ Database API: Test database schemas when filtering for upload allowed
+ for a DB connection that has file uploads disabled
+ """
+ database = db.session.query(Database).filter_by(database_name="examples").one()
+ self.login(ADMIN_USERNAME)
+ arguments = {"upload_allowed": True}
+ uri = f"api/v1/database/{database.id}/schemas/?q={prison.dumps(arguments)}"
+ rv = self.client.get(uri)
+ assert rv.status_code == 400
+ data = json.loads(rv.data.decode("utf-8"))
+ assert data["message"] == "File upload is disabled on this database connection"
+
def test_database_tables(self):
"""
Database API: Test database tables