mirror of https://github.com/apache/superset.git
feat: handle chart/data API errors (#14040)
This commit is contained in:
parent
ec3f8d07f4
commit
3d357c661c
|
@ -65,7 +65,7 @@ from superset.charts.schemas import (
|
|||
from superset.commands.exceptions import CommandInvalidError
|
||||
from superset.commands.importers.v1.utils import get_contents_from_bundle
|
||||
from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod
|
||||
from superset.exceptions import QueryObjectValidationError, SupersetSecurityException
|
||||
from superset.exceptions import QueryObjectValidationError
|
||||
from superset.extensions import event_logger
|
||||
from superset.models.slice import Slice
|
||||
from superset.tasks.thumbnails import cache_chart_thumbnail
|
||||
|
@ -500,7 +500,6 @@ class ChartRestApi(BaseSupersetModelRestApi):
|
|||
|
||||
@expose("/data", methods=["POST"])
|
||||
@protect()
|
||||
@safe
|
||||
@statsd_metrics
|
||||
@event_logger.log_this_with_context(
|
||||
action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.data",
|
||||
|
@ -569,8 +568,6 @@ class ChartRestApi(BaseSupersetModelRestApi):
|
|||
"Request is incorrect: %(error)s", error=error.normalized_messages()
|
||||
)
|
||||
)
|
||||
except SupersetSecurityException:
|
||||
return self.response_401()
|
||||
|
||||
# TODO: support CSV, SQL query and other non-JSON types
|
||||
if (
|
||||
|
@ -591,7 +588,6 @@ class ChartRestApi(BaseSupersetModelRestApi):
|
|||
|
||||
@expose("/data/<cache_key>", methods=["GET"])
|
||||
@protect()
|
||||
@safe
|
||||
@statsd_metrics
|
||||
@event_logger.log_this_with_context(
|
||||
action=lambda self, *args, **kwargs: f"{self.__class__.__name__}"
|
||||
|
@ -641,9 +637,6 @@ class ChartRestApi(BaseSupersetModelRestApi):
|
|||
return self.response_400(
|
||||
message=_("Request is incorrect: %(error)s", error=error.messages)
|
||||
)
|
||||
except SupersetSecurityException as exc:
|
||||
logger.info(exc)
|
||||
return self.response_401()
|
||||
|
||||
return self.get_data_response(command, True)
|
||||
|
||||
|
|
|
@ -41,6 +41,14 @@ class SupersetException(Exception):
|
|||
class SupersetErrorException(SupersetException):
|
||||
"""Exceptions with a single SupersetErrorType associated with them"""
|
||||
|
||||
def __init__(self, error: SupersetError) -> None:
|
||||
super().__init__(error.message)
|
||||
self.error = error
|
||||
|
||||
|
||||
class SupersetErrorFromParamsException(SupersetErrorException):
|
||||
"""Exceptions that pass in parameters to construct a SupersetError"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
error_type: SupersetErrorType,
|
||||
|
@ -48,10 +56,11 @@ class SupersetErrorException(SupersetException):
|
|||
level: ErrorLevel,
|
||||
extra: Optional[Dict[str, Any]] = None,
|
||||
) -> None:
|
||||
super().__init__(message)
|
||||
self.error = SupersetError(
|
||||
super().__init__(
|
||||
SupersetError(
|
||||
error_type=error_type, message=message, level=level, extra=extra or {}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class SupersetErrorsException(SupersetException):
|
||||
|
@ -62,11 +71,11 @@ class SupersetErrorsException(SupersetException):
|
|||
self.errors = errors
|
||||
|
||||
|
||||
class SupersetTimeoutException(SupersetErrorException):
|
||||
class SupersetTimeoutException(SupersetErrorFromParamsException):
|
||||
status = 408
|
||||
|
||||
|
||||
class SupersetGenericDBErrorException(SupersetErrorException):
|
||||
class SupersetGenericDBErrorException(SupersetErrorFromParamsException):
|
||||
status = 400
|
||||
|
||||
def __init__(
|
||||
|
@ -80,7 +89,7 @@ class SupersetGenericDBErrorException(SupersetErrorException):
|
|||
)
|
||||
|
||||
|
||||
class SupersetTemplateParamsErrorException(SupersetErrorException):
|
||||
class SupersetTemplateParamsErrorException(SupersetErrorFromParamsException):
|
||||
status = 400
|
||||
|
||||
def __init__(
|
||||
|
@ -94,14 +103,13 @@ class SupersetTemplateParamsErrorException(SupersetErrorException):
|
|||
)
|
||||
|
||||
|
||||
class SupersetSecurityException(SupersetException):
|
||||
class SupersetSecurityException(SupersetErrorException):
|
||||
status = 401
|
||||
|
||||
def __init__(
|
||||
self, error: SupersetError, payload: Optional[Dict[str, Any]] = None
|
||||
) -> None:
|
||||
super().__init__(error.message)
|
||||
self.error = error
|
||||
super().__init__(error)
|
||||
self.payload = payload
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_s
|
|||
from tests.test_app import app
|
||||
from superset.charts.commands.data import ChartDataCommand
|
||||
from superset.connectors.sqla.models import SqlaTable, TableColumn
|
||||
from superset.errors import SupersetErrorType
|
||||
from superset.extensions import async_query_manager, cache_manager, db
|
||||
from superset.models.annotations import AnnotationLayer
|
||||
from superset.models.core import Database, FavStar, FavStarClassName
|
||||
|
@ -47,6 +48,7 @@ from superset.models.slice import Slice
|
|||
from superset.utils import core as utils
|
||||
from superset.utils.core import AnnotationType, get_example_database, get_main_database
|
||||
|
||||
|
||||
from tests.base_api_tests import ApiOwnersTestCaseMixin
|
||||
from tests.base_tests import SupersetTestCase, post_assert_metric, test_client
|
||||
|
||||
|
@ -1345,6 +1347,11 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixin):
|
|||
payload = get_query_context("birth_names")
|
||||
rv = self.post_assert_metric(CHART_DATA_URI, payload, "data")
|
||||
self.assertEqual(rv.status_code, 401)
|
||||
response_payload = json.loads(rv.data.decode("utf-8"))
|
||||
assert (
|
||||
response_payload["errors"][0]["error_type"]
|
||||
== SupersetErrorType.DATASOURCE_SECURITY_ACCESS_ERROR
|
||||
)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_jinja_filter_request(self):
|
||||
|
|
Loading…
Reference in New Issue