Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: remove deprecated apis stop_query, queries, search_queries #24360

Merged
merged 8 commits into from
Jun 13, 2023
3 changes: 0 additions & 3 deletions RESOURCES/STANDARD_ROLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
|can user slices on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can favstar on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can import dashboards on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can search queries on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|can sqllab viz on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|can schemas on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can sqllab history on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
Expand Down Expand Up @@ -95,8 +94,6 @@
|can sqllab table viz on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|can profile on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can available domains on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can queries on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can stop query on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|can request access on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can dashboard on Superset|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|can post on TableSchemaView|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
Expand Down
1 change: 1 addition & 0 deletions UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ assists people when migrating to a new version.

### Breaking Changes

- [24360](https://github.com/apache/superset/pull/24360): Removed deprecated APIs `/superset/stop_query/...`, `/superset/queries/...`, `/superset/search_queries`
- [24198](https://github.com/apache/superset/pull/24198) The FAB views `User Registrations` and `User's Statistics` have been changed to Admin only. To re-enable them for non-admin users, please add the following perms to your custom role: `menu access on User's Statistics` and `menu access on User Registrations`.
- [24354](https://github.com/apache/superset/pull/24354): Removed deprecated APIs `/superset/testconn`, `/superset/validate_sql_json/`, `/superset/schemas_access_for_file_upload`, `/superset/extra_table_metadata`
- [24381](https://github.com/apache/superset/pull/24381): Removed deprecated API `/superset/available_domains/`
Expand Down
2 changes: 0 additions & 2 deletions superset/security/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,7 @@ class SupersetSecurityManager( # pylint: disable=too-many-public-methods
("can_sqllab_viz", "Superset"),
("can_sqllab_table_viz", "Superset"), # Deprecated permission remove on 3.0.0
("can_sqllab", "Superset"),
("can_stop_query", "Superset"), # Deprecated permission remove on 3.0.0
("can_test_conn", "Superset"), # Deprecated permission remove on 3.0.0
("can_search_queries", "Superset"), # Deprecated permission remove on 3.0.0
("can_activate", "TabStateView"),
("can_get", "TabStateView"),
("can_delete_query", "TabStateView"),
Expand Down
140 changes: 0 additions & 140 deletions superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from typing import Any, Callable, cast
from urllib import parse

import backoff
import simplejson as json
from flask import abort, flash, g, redirect, render_template, request, Response
from flask_appbuilder import expose
Expand All @@ -44,21 +43,18 @@
event_logger,
is_feature_enabled,
security_manager,
sql_lab,
viz,
)
from superset.charts.commands.exceptions import ChartNotFoundError
from superset.charts.dao import ChartDAO
from superset.common.chart_data import ChartDataResultFormat, ChartDataResultType
from superset.common.db_query_status import QueryStatus
from superset.connectors.base.models import BaseDatasource
from superset.connectors.sqla.models import (
AnnotationDatasource,
SqlaTable,
SqlMetric,
TableColumn,
)
from superset.constants import QUERY_EARLY_CANCEL_KEY
from superset.dashboards.commands.exceptions import DashboardAccessDeniedError
from superset.dashboards.commands.importers.v0 import ImportDashboardsCommand
from superset.dashboards.dao import DashboardDAO
Expand All @@ -71,7 +67,6 @@
from superset.exceptions import (
CacheLoadError,
DatabaseNotFound,
SupersetCancelQueryException,
SupersetErrorException,
SupersetException,
SupersetGenericErrorException,
Expand All @@ -95,7 +90,6 @@
from superset.utils.async_query_manager import AsyncQueryTokenException
from superset.utils.cache import etag_cache
from superset.utils.core import DatasourceType, get_user_id, ReservedUrlParameters
from superset.utils.dates import now_as_float
from superset.views.base import (
api,
BaseSupersetView,
Expand Down Expand Up @@ -1566,44 +1560,6 @@ def extra_table_metadata( # pylint: disable=no-self-use
def theme(self) -> FlaskResponse:
return self.render_template("superset/theme.html")

@has_access_api
@handle_api_exception
@expose("/stop_query/", methods=("POST",))
@event_logger.log_this
@backoff.on_exception(
backoff.constant,
Exception,
interval=1,
on_backoff=lambda details: db.session.rollback(),
on_giveup=lambda details: db.session.rollback(),
max_tries=5,
)
@deprecated(new_target="/api/v1/query/stop")
def stop_query(self) -> FlaskResponse:
client_id = request.form.get("client_id")
query = db.session.query(Query).filter_by(client_id=client_id).one()
if query.status in [
QueryStatus.FAILED,
QueryStatus.SUCCESS,
QueryStatus.TIMED_OUT,
]:
logger.warning(
"Query with client_id could not be stopped: query already complete",
)
return self.json_response("OK")

if not sql_lab.cancel_query(query):
raise SupersetCancelQueryException("Could not cancel query")

query.status = QueryStatus.STOPPED
# Add the stop identity attribute because the sqlalchemy thread is unsafe
# because of multiple updates to the status in the query table
query.set_extra_json_key(QUERY_EARLY_CANCEL_KEY, True)
query.end_time = now_as_float()
db.session.commit()

return self.json_response("OK")

@api
@handle_api_exception
@has_access
Expand All @@ -1628,102 +1584,6 @@ def fetch_datasource_metadata(self) -> FlaskResponse: # pylint: disable=no-self
datasource.raise_for_access()
return json_success(json.dumps(sanitize_datasource_data(datasource.data)))

@has_access_api
@event_logger.log_this
@expose("/queries/<float:last_updated_ms>")
@expose("/queries/<int:last_updated_ms>")
@deprecated(new_target="api/v1/query/updated_since")
def queries(self, last_updated_ms: float | int) -> FlaskResponse:
"""
Get the updated queries.

:param last_updated_ms: Unix time (milliseconds)
"""

return self.queries_exec(last_updated_ms)

@staticmethod
def queries_exec(last_updated_ms: float | int) -> FlaskResponse:
stats_logger.incr("queries")
if not get_user_id():
return json_error_response(
"Please login to access the queries.", status=403
)

# UTC date time, same that is stored in the DB.
last_updated_dt = datetime.utcfromtimestamp(last_updated_ms / 1000)

sql_queries = (
db.session.query(Query)
.filter(Query.user_id == get_user_id(), Query.changed_on >= last_updated_dt)
.all()
)
dict_queries = {q.client_id: q.to_dict() for q in sql_queries}
return json_success(json.dumps(dict_queries, default=utils.json_int_dttm_ser))

@has_access
@event_logger.log_this
@expose("/search_queries")
@deprecated(new_target="api/v1/query/")
def search_queries(self) -> FlaskResponse: # pylint: disable=no-self-use
"""
Search for previously run sqllab queries. Used for Sqllab Query Search
page /superset/sqllab#search.

Custom permission can_only_search_queries_owned restricts queries
to only queries run by current user.

:returns: Response with list of sql query dicts
"""
if security_manager.can_access_all_queries():
search_user_id = request.args.get("user_id")
elif request.args.get("user_id") is not None:
try:
search_user_id = int(cast(int, request.args.get("user_id")))
except ValueError:
return Response(status=400, mimetype="application/json")
if search_user_id != get_user_id():
return Response(status=403, mimetype="application/json")
else:
search_user_id = get_user_id()
database_id = request.args.get("database_id")
search_text = request.args.get("search_text")
# From and To time stamp should be Epoch timestamp in seconds

query = db.session.query(Query)
if search_user_id:
# Filter on user_id
query = query.filter(Query.user_id == search_user_id)

if database_id:
# Filter on db Id
query = query.filter(Query.database_id == database_id)

if status := request.args.get("status"):
# Filter on status
query = query.filter(Query.status == status)

if search_text:
# Filter on search text
query = query.filter(Query.sql.like(f"%{search_text}%"))

if from_time := request.args.get("from"):
query = query.filter(Query.start_time > int(from_time))

if to_time := request.args.get("to"):
query = query.filter(Query.start_time < int(to_time))

query_limit = config["QUERY_SEARCH_LIMIT"]
sql_queries = query.order_by(Query.start_time.asc()).limit(query_limit).all()

dict_queries = [q.to_dict() for q in sql_queries]

return Response(
json.dumps(dict_queries, default=utils.json_int_dttm_ser),
status=200,
mimetype="application/json",
)

@app.errorhandler(500)
def show_traceback(self) -> FlaskResponse: # pylint: disable=no-self-use
return (
Expand Down
23 changes: 0 additions & 23 deletions tests/integration_tests/core_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1243,29 +1243,6 @@ def test_dashboard_injected_exceptions(self, mock_db_connection_mutator):
data = self.get_resp(url)
self.assertIn("Error message", data)

@mock.patch("superset.sql_lab.cancel_query")
@mock.patch("superset.views.core.db.session")
def test_stop_query_not_implemented(
self, mock_superset_db_session, mock_sql_lab_cancel_query
):
"""
Handles stop query when the DB engine spec does not
have a cancel query method.
"""
form_data = {"client_id": "foo"}
query_mock = mock.Mock()
query_mock.client_id = "foo"
query_mock.status = QueryStatus.RUNNING
self.login(username="admin")
mock_superset_db_session.query().filter_by().one().return_value = query_mock
mock_sql_lab_cancel_query.return_value = False
rv = self.client.post(
"/superset/stop_query/",
data={"form_data": json.dumps(form_data)},
)

assert rv.status_code == 422

@pytest.mark.usefixtures("load_energy_table_with_slice")
@mock.patch("superset.explore.form_data.commands.create.CreateFormDataCommand.run")
def test_explore_redirect(self, mock_command: mock.Mock):
Expand Down
Loading