From 7a68cb7ca0d00294e10b86a2a4f29268ea5cb965 Mon Sep 17 00:00:00 2001
From: David Aaron Suddjian <1858430+suddjian@users.noreply.github.com>
Date: Tue, 17 Dec 2019 16:17:49 -0800
Subject: [PATCH] factor out datasource_access_request model (#8809)
---
superset/models/__init__.py | 2 +-
superset/models/core.py | 68 -------------
superset/models/datasource_access_request.py | 101 +++++++++++++++++++
superset/views/core.py | 3 +-
tests/access_tests.py | 3 +-
tests/base_tests.py | 3 +-
tests/core_tests.py | 3 +-
7 files changed, 110 insertions(+), 73 deletions(-)
create mode 100644 superset/models/datasource_access_request.py
diff --git a/superset/models/__init__.py b/superset/models/__init__.py
index 17e7d188dc..c7eed13b4a 100644
--- a/superset/models/__init__.py
+++ b/superset/models/__init__.py
@@ -14,4 +14,4 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-from . import core, schedules, sql_lab, user_attributes
+from . import core, datasource_access_request, schedules, sql_lab, user_attributes
diff --git a/superset/models/core.py b/superset/models/core.py
index 79ff3b0483..b65547ab93 100755
--- a/superset/models/core.py
+++ b/superset/models/core.py
@@ -1322,74 +1322,6 @@ class FavStar(Model): # pylint: disable=too-few-public-methods
dttm = Column(DateTime, default=datetime.utcnow)
-class DatasourceAccessRequest(Model, AuditMixinNullable):
- """ORM model for the access requests for datasources and dbs."""
-
- __tablename__ = "access_request"
- id = Column(Integer, primary_key=True) # pylint: disable=invalid-name
-
- datasource_id = Column(Integer)
- datasource_type = Column(String(200))
-
- ROLES_BLACKLIST = set(config["ROBOT_PERMISSION_ROLES"])
-
- @property
- def cls_model(self) -> Type["BaseDatasource"]:
- return ConnectorRegistry.sources[self.datasource_type]
-
- @property
- def username(self) -> Markup:
- return self.creator()
-
- @property
- def datasource(self) -> "BaseDatasource":
- return self.get_datasource
-
- @datasource.getter # type: ignore
- @utils.memoized
- def get_datasource(self) -> "BaseDatasource":
- ds = db.session.query(self.cls_model).filter_by(id=self.datasource_id).first()
- return ds
-
- @property
- def datasource_link(self) -> Optional[Markup]:
- return self.datasource.link # pylint: disable=no-member
-
- @property
- def roles_with_datasource(self) -> str:
- action_list = ""
- perm = self.datasource.perm # pylint: disable=no-member
- pv = security_manager.find_permission_view_menu("datasource_access", perm)
- for role in pv.role:
- if role.name in self.ROLES_BLACKLIST:
- continue
- # pylint: disable=no-member
- href = (
- f"/superset/approve?datasource_type={self.datasource_type}&"
- f"datasource_id={self.datasource_id}&"
- f"created_by={self.created_by.username}&role_to_grant={role.name}"
- )
- link = 'Grant {} Role'.format(href, role.name)
- action_list = action_list + "
" + link + ""
- return ""
-
- @property
- def user_roles(self) -> str:
- action_list = ""
- for role in self.created_by.roles: # pylint: disable=no-member
- # pylint: disable=no-member
- href = (
- f"/superset/approve?datasource_type={self.datasource_type}&"
- f"datasource_id={self.datasource_id}&"
- f"created_by={self.created_by.username}&role_to_extend={role.name}"
- )
- link = 'Extend {} Role'.format(href, role.name)
- if role.name in self.ROLES_BLACKLIST:
- link = "{} Role".format(role.name)
- action_list = action_list + "" + link + ""
- return ""
-
-
# events for updating tags
if is_feature_enabled("TAGGING_SYSTEM"):
sqla.event.listen(Slice, "after_insert", ChartUpdater.after_insert)
diff --git a/superset/models/datasource_access_request.py b/superset/models/datasource_access_request.py
new file mode 100644
index 0000000000..803a91115f
--- /dev/null
+++ b/superset/models/datasource_access_request.py
@@ -0,0 +1,101 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from typing import Optional, Type, TYPE_CHECKING
+
+from flask import Markup
+from flask_appbuilder import Model
+from sqlalchemy import Column, Integer, String
+
+from superset import app, db, security_manager
+from superset.connectors.connector_registry import ConnectorRegistry
+from superset.models.helpers import AuditMixinNullable
+from superset.utils import core as utils
+
+if TYPE_CHECKING:
+ from superset.connectors.base.models import ( # pylint: disable=unused-import
+ BaseDatasource,
+ )
+
+config = app.config
+
+
+class DatasourceAccessRequest(Model, AuditMixinNullable):
+ """ORM model for the access requests for datasources and dbs."""
+
+ __tablename__ = "access_request"
+ id = Column(Integer, primary_key=True) # pylint: disable=invalid-name
+
+ datasource_id = Column(Integer)
+ datasource_type = Column(String(200))
+
+ ROLES_BLACKLIST = set(config["ROBOT_PERMISSION_ROLES"])
+
+ @property
+ def cls_model(self) -> Type["BaseDatasource"]:
+ return ConnectorRegistry.sources[self.datasource_type]
+
+ @property
+ def username(self) -> Markup:
+ return self.creator()
+
+ @property
+ def datasource(self) -> "BaseDatasource":
+ return self.get_datasource
+
+ @datasource.getter # type: ignore
+ @utils.memoized
+ def get_datasource(self) -> "BaseDatasource":
+ ds = db.session.query(self.cls_model).filter_by(id=self.datasource_id).first()
+ return ds
+
+ @property
+ def datasource_link(self) -> Optional[Markup]:
+ return self.datasource.link # pylint: disable=no-member
+
+ @property
+ def roles_with_datasource(self) -> str:
+ action_list = ""
+ perm = self.datasource.perm # pylint: disable=no-member
+ pv = security_manager.find_permission_view_menu("datasource_access", perm)
+ for role in pv.role:
+ if role.name in self.ROLES_BLACKLIST:
+ continue
+ # pylint: disable=no-member
+ href = (
+ f"/superset/approve?datasource_type={self.datasource_type}&"
+ f"datasource_id={self.datasource_id}&"
+ f"created_by={self.created_by.username}&role_to_grant={role.name}"
+ )
+ link = 'Grant {} Role'.format(href, role.name)
+ action_list = action_list + "" + link + ""
+ return ""
+
+ @property
+ def user_roles(self) -> str:
+ action_list = ""
+ for role in self.created_by.roles: # pylint: disable=no-member
+ # pylint: disable=no-member
+ href = (
+ f"/superset/approve?datasource_type={self.datasource_type}&"
+ f"datasource_id={self.datasource_id}&"
+ f"created_by={self.created_by.username}&role_to_extend={role.name}"
+ )
+ link = 'Extend {} Role'.format(href, role.name)
+ if role.name in self.ROLES_BLACKLIST:
+ link = "{} Role".format(role.name)
+ action_list = action_list + "" + link + ""
+ return ""
diff --git a/superset/views/core.py b/superset/views/core.py
index fe33bf9c3c..0869c611cb 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -77,6 +77,7 @@ from superset.exceptions import (
SupersetTimeoutException,
)
from superset.jinja_context import get_template_processor
+from superset.models.datasource_access_request import DatasourceAccessRequest
from superset.models.sql_lab import Query, TabState
from superset.models.user_attributes import UserAttribute
from superset.sql_parse import ParsedQuery
@@ -117,7 +118,7 @@ config = app.config
CACHE_DEFAULT_TIMEOUT = config["CACHE_DEFAULT_TIMEOUT"]
SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT = config["SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT"]
stats_logger = config["STATS_LOGGER"]
-DAR = models.DatasourceAccessRequest
+DAR = DatasourceAccessRequest
QueryStatus = utils.QueryStatus
DATABASE_KEYS = [
diff --git a/tests/access_tests.py b/tests/access_tests.py
index 7b0be43c04..63cbfb5c70 100644
--- a/tests/access_tests.py
+++ b/tests/access_tests.py
@@ -26,6 +26,7 @@ from superset.connectors.connector_registry import ConnectorRegistry
from superset.connectors.druid.models import DruidDatasource
from superset.connectors.sqla.models import SqlaTable
from superset.models import core as models
+from superset.models.datasource_access_request import DatasourceAccessRequest
from .base_tests import SupersetTestCase
@@ -83,7 +84,7 @@ def create_access_request(session, ds_type, ds_name, role_name, user_name):
security_manager.add_permission_role(
security_manager.find_role(role_name), ds_perm_view
)
- access_request = models.DatasourceAccessRequest(
+ access_request = DatasourceAccessRequest(
datasource_id=ds.id,
datasource_type=ds_type,
created_by_fk=security_manager.find_user(username=user_name).id,
diff --git a/tests/base_tests.py b/tests/base_tests.py
index 666102c43c..4f82e2ee0e 100644
--- a/tests/base_tests.py
+++ b/tests/base_tests.py
@@ -31,6 +31,7 @@ from superset.connectors.druid.models import DruidCluster, DruidDatasource
from superset.connectors.sqla.models import SqlaTable
from superset.models import core as models
from superset.models.core import Database
+from superset.models.datasource_access_request import DatasourceAccessRequest
from superset.utils.core import get_example_database
FAKE_DB_NAME = "fake_db_100"
@@ -158,7 +159,7 @@ class SupersetTestCase(TestCase):
return json.loads(resp)
def get_access_requests(self, username, ds_type, ds_id):
- DAR = models.DatasourceAccessRequest
+ DAR = DatasourceAccessRequest
return (
db.session.query(DAR)
.filter(
diff --git a/tests/core_tests.py b/tests/core_tests.py
index ae7cf633e3..59092bd0a4 100644
--- a/tests/core_tests.py
+++ b/tests/core_tests.py
@@ -40,6 +40,7 @@ from superset.connectors.sqla.models import SqlaTable
from superset.db_engine_specs.base import BaseEngineSpec
from superset.db_engine_specs.mssql import MssqlEngineSpec
from superset.models import core as models
+from superset.models.datasource_access_request import DatasourceAccessRequest
from superset.models.sql_lab import Query
from superset.utils import core as utils
from superset.views import core as views
@@ -55,7 +56,7 @@ class CoreTests(SupersetTestCase):
def setUp(self):
db.session.query(Query).delete()
- db.session.query(models.DatasourceAccessRequest).delete()
+ db.session.query(DatasourceAccessRequest).delete()
db.session.query(models.Log).delete()
self.table_ids = {
tbl.table_name: tbl.id for tbl in (db.session.query(SqlaTable).all())