mirror of https://github.com/apache/superset.git
feat(dashboard_rbac): add support for related roles (#13035)
This commit is contained in:
parent
10296651fb
commit
312cbf736c
|
@ -54,6 +54,7 @@ from superset.dashboards.filters import (
|
|||
DashboardFavoriteFilter,
|
||||
DashboardFilter,
|
||||
DashboardTitleOrSlugFilter,
|
||||
FilterRelatedRoles,
|
||||
)
|
||||
from superset.dashboards.schemas import (
|
||||
DashboardPostSchema,
|
||||
|
@ -192,12 +193,14 @@ class DashboardRestApi(BaseSupersetModelRestApi):
|
|||
order_rel_fields = {
|
||||
"slices": ("slice_name", "asc"),
|
||||
"owners": ("first_name", "asc"),
|
||||
"roles": ("name", "asc"),
|
||||
}
|
||||
related_field_filters = {
|
||||
"owners": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
"roles": RelatedFieldFilter("name", FilterRelatedRoles),
|
||||
"created_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
}
|
||||
allowed_rel_fields = {"owners", "created_by"}
|
||||
allowed_rel_fields = {"owners", "roles", "created_by"}
|
||||
|
||||
openapi_spec_tag = "Dashboards"
|
||||
""" Override the name set for this collection of endpoints """
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from typing import Any
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
from typing import Any, Optional
|
||||
|
||||
from flask_appbuilder.security.sqla.models import Role
|
||||
from flask_babel import lazy_gettext as _
|
||||
|
@ -29,7 +31,7 @@ from superset.views.base import BaseFilter, get_user_roles, is_user_admin
|
|||
from superset.views.base_api import BaseFavoriteFilter
|
||||
|
||||
|
||||
class DashboardTitleOrSlugFilter(BaseFilter): # pylint: disable=too-few-public-methods
|
||||
class DashboardTitleOrSlugFilter(BaseFilter):
|
||||
name = _("Title or Slug")
|
||||
arg_name = "title_or_slug"
|
||||
|
||||
|
@ -45,9 +47,7 @@ class DashboardTitleOrSlugFilter(BaseFilter): # pylint: disable=too-few-public-
|
|||
)
|
||||
|
||||
|
||||
class DashboardFavoriteFilter(
|
||||
BaseFavoriteFilter
|
||||
): # pylint: disable=too-few-public-methods
|
||||
class DashboardFavoriteFilter(BaseFavoriteFilter):
|
||||
"""
|
||||
Custom filter for the GET list that filters all dashboards that a user has favored
|
||||
"""
|
||||
|
@ -57,7 +57,7 @@ class DashboardFavoriteFilter(
|
|||
model = Dashboard
|
||||
|
||||
|
||||
class DashboardFilter(BaseFilter): # pylint: disable=too-few-public-methods
|
||||
class DashboardFilter(BaseFilter):
|
||||
"""
|
||||
List dashboards with the following criteria:
|
||||
1. Those which the user owns
|
||||
|
@ -138,3 +138,23 @@ class DashboardFilter(BaseFilter): # pylint: disable=too-few-public-methods
|
|||
)
|
||||
|
||||
return query
|
||||
|
||||
|
||||
class FilterRelatedRoles(BaseFilter):
|
||||
"""
|
||||
A filter to allow searching for related roles of a resource.
|
||||
|
||||
Use in the api by adding something like:
|
||||
related_field_filters = {
|
||||
"roles": RelatedFieldFilter("name", FilterRelatedRoles),
|
||||
}
|
||||
"""
|
||||
|
||||
name = _("Role")
|
||||
arg_name = "roles"
|
||||
|
||||
def apply(self, query: Query, value: Optional[Any]) -> Query:
|
||||
role_model = security_manager.role_model
|
||||
if value:
|
||||
return query.filter(role_model.name.ilike(f"%{value}%"),)
|
||||
return query
|
||||
|
|
|
@ -29,7 +29,7 @@ import yaml
|
|||
from sqlalchemy.sql import func
|
||||
|
||||
from freezegun import freeze_time
|
||||
from sqlalchemy import and_, or_
|
||||
from sqlalchemy import and_
|
||||
from superset import db, security_manager
|
||||
from superset.models.dashboard import Dashboard
|
||||
from superset.models.core import FavStar, FavStarClassName
|
||||
|
@ -1343,3 +1343,37 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
|||
assert response == {
|
||||
"message": {"metadata.yaml": {"type": ["Must be equal to Dashboard."]}}
|
||||
}
|
||||
|
||||
def test_get_all_related_roles(self):
|
||||
"""
|
||||
API: Test get filter related roles
|
||||
"""
|
||||
self.login(username="admin")
|
||||
uri = f"api/v1/dashboard/related/roles"
|
||||
|
||||
rv = self.client.get(uri)
|
||||
assert rv.status_code == 200
|
||||
response = json.loads(rv.data.decode("utf-8"))
|
||||
roles = db.session.query(security_manager.role_model).all()
|
||||
expected_roles = [str(role) for role in roles]
|
||||
assert response["count"] == len(roles)
|
||||
|
||||
response_roles = [result["text"] for result in response["result"]]
|
||||
for expected_role in expected_roles:
|
||||
assert expected_role in response_roles
|
||||
|
||||
def test_get_filter_related_roles(self):
|
||||
"""
|
||||
API: Test get filter related roles
|
||||
"""
|
||||
self.login(username="admin")
|
||||
argument = {"filter": "alpha"}
|
||||
uri = f"api/v1/dashboard/related/roles?q={prison.dumps(argument)}"
|
||||
|
||||
rv = self.client.get(uri)
|
||||
assert rv.status_code == 200
|
||||
response = json.loads(rv.data.decode("utf-8"))
|
||||
assert response["count"] == 1
|
||||
|
||||
response_roles = [result["text"] for result in response["result"]]
|
||||
assert "Alpha" in response_roles
|
||||
|
|
Loading…
Reference in New Issue