You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by su...@apache.org on 2021/02/26 00:13:01 UTC

[superset] 02/02: fix(dashboard): accept slug in place of id in url

This is an automated email from the ASF dual-hosted git repository.

suddjian pushed a commit to branch get-dashboard-by-slug
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 9b44b9262aace719eae18b32ffe228fe94eba5c0
Author: David Aaron Suddjian <aa...@gmail.com>
AuthorDate: Thu Feb 25 15:58:57 2021 -0800

    fix(dashboard): accept slug in place of id in url
---
 superset/dashboards/api.py     | 53 +++++++++++++++++++++++++++++++++++++++++-
 superset/dashboards/dao.py     | 18 ++++++++++++--
 superset/dashboards/schemas.py | 43 +++++++++++++++++++++++++++++++++-
 3 files changed, 110 insertions(+), 4 deletions(-)

diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py
index 7678711..f0e1f8b 100644
--- a/superset/dashboards/api.py
+++ b/superset/dashboards/api.py
@@ -60,6 +60,7 @@ from superset.dashboards.filters import (
 from superset.dashboards.schemas import (
     DashboardPostSchema,
     DashboardPutSchema,
+    DashboardResponseSchema,
     get_delete_ids_schema,
     get_export_ids_schema,
     get_fav_star_ids_schema,
@@ -190,6 +191,7 @@ class DashboardRestApi(BaseSupersetModelRestApi):
     add_model_schema = DashboardPostSchema()
     edit_model_schema = DashboardPutSchema()
     chart_entity_response_schema = ChartEntityResponseSchema()
+    dashboard_response_schema = DashboardResponseSchema()
 
     base_filters = [["slice", DashboardFilter, lambda: []]]
 
@@ -207,7 +209,11 @@ class DashboardRestApi(BaseSupersetModelRestApi):
 
     openapi_spec_tag = "Dashboards"
     """ Override the name set for this collection of endpoints """
-    openapi_spec_component_schemas = (ChartEntityResponseSchema, GetFavStarIdsSchema)
+    openapi_spec_component_schemas = (
+        ChartEntityResponseSchema,
+        DashboardResponseSchema,
+        GetFavStarIdsSchema,
+    )
     apispec_parameter_schemas = {
         "get_delete_ids_schema": get_delete_ids_schema,
         "get_export_ids_schema": get_export_ids_schema,
@@ -222,6 +228,51 @@ class DashboardRestApi(BaseSupersetModelRestApi):
             self.include_route_methods = self.include_route_methods | {"thumbnail"}
         super().__init__()
 
+    @expose("/<id_or_slug>", methods=["GET"])
+    @protect()
+    @safe
+    @statsd_metrics
+    @event_logger.log_this_with_context(
+        action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.get",
+        log_to_statsd=False,
+    )
+    def get(self, id_or_slug: str) -> Response:
+        """Gets a dashboard
+        ---
+        get:
+          description: >-
+            Get a dashboard
+          parameters:
+          - in: path
+            schema:
+              type: string
+            name: id_or_slug
+          responses:
+            200:
+              description: Dashboard
+              content:
+                application/json:
+                  schema:
+                    type: object
+                    properties:
+                      result:
+                        $ref: '#/components/schemas/DashboardResponseSchema'
+            302:
+              description: Redirects to the current digest
+            400:
+              $ref: '#/components/responses/400'
+            401:
+              $ref: '#/components/responses/401'
+            404:
+              $ref: '#/components/responses/404'
+        """
+        try:
+            dash = Dashboard.get(id_or_slug)
+            result = self.dashboard_response_schema.dump(dash)
+            return self.response(200, result=result)
+        except DashboardNotFoundError:
+            return self.response_404()
+
     @expose("/<pk>/charts", methods=["GET"])
     @protect()
     @safe
diff --git a/superset/dashboards/dao.py b/superset/dashboards/dao.py
index 142331e..3e5b35b 100644
--- a/superset/dashboards/dao.py
+++ b/superset/dashboards/dao.py
@@ -25,9 +25,9 @@ from sqlalchemy.orm import contains_eager
 from superset.dao.base import BaseDAO
 from superset.dashboards.commands.exceptions import DashboardNotFoundError
 from superset.dashboards.filters import DashboardFilter
-from superset.extensions import db
+from superset.extensions import db, security_manager
 from superset.models.core import FavStar, FavStarClassName
-from superset.models.dashboard import Dashboard
+from superset.models.dashboard import Dashboard, dashboard_user
 from superset.models.slice import Slice
 from superset.utils.dashboard_filter_scopes_converter import copy_filter_scopes
 
@@ -39,6 +39,20 @@ class DashboardDAO(BaseDAO):
     base_filter = DashboardFilter
 
     @staticmethod
+    def get_dashboard(id_or_slug: str) -> Dashboard:
+        query = db.session.query(Dashboard).filter(
+            Dashboard.id_or_slug_filter(id_or_slug)
+        )
+        # Apply dashboard base filters
+        query = DashboardFilter("id", SQLAInterface(Dashboard, db.session)).apply(
+            query, None
+        )
+        dashboard = query.one_or_none()
+        if not dashboard:
+            raise DashboardNotFoundError()
+        return dashboard
+
+    @staticmethod
     def get_charts_for_dashboard(dashboard_id: int) -> List[Slice]:
         query = (
             db.session.query(Dashboard)
diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py
index 360f94f..46ce37b 100644
--- a/superset/dashboards/schemas.py
+++ b/superset/dashboards/schemas.py
@@ -61,7 +61,9 @@ published_description = (
     "Determines whether or not this dashboard is visible in "
     "the list of all dashboards."
 )
-
+charts_description = (
+    "The names of the dashboard's charts. Names are used for legacy reasons."
+)
 
 openapi_spec_methods_override = {
     "get": {"get": {"description": "Get a dashboard detail information."}},
@@ -121,6 +123,45 @@ class DashboardJSONMetadataSchema(Schema):
     label_colors = fields.Dict()
 
 
+class UserSchema(Schema):
+    id = fields.Int()
+    username = fields.String()
+    first_name = fields.String()
+    last_name = fields.String()
+
+
+class RolesSchema(Schema):
+    id = fields.Int()
+    name = fields.String()
+
+
+class DatasourceSchema(Schema):
+    id = fields.Int()
+    name = fields.String()
+    description = fields.String()
+
+
+class DashboardResponseSchema(Schema):
+    id = fields.Int()
+    slug = fields.String()
+    url = fields.String()
+    dashboard_title = fields.String(description=dashboard_title_description)
+    thumbnail_url = fields.String()
+    published = fields.Boolean()
+    css = fields.String(description=css_description)
+    json_metadata = fields.String(description=json_metadata_description)
+    position_json = fields.String(description=position_json_description)
+    changed_by_name = fields.String()
+    changed_by_url = fields.String()
+    changed_by = fields.Nested(UserSchema)
+    changed_on = fields.DateTime()
+    charts = fields.List(fields.String(description=charts_description))
+    owners = fields.List(fields.Nested(UserSchema))
+    roles = fields.List(fields.Nested(RolesSchema))
+    datasources = fields.List(fields.Nested(DatasourceSchema))
+    table_names = fields.String()  # legacy nonsense
+
+
 class BaseDashboardSchema(Schema):
     # pylint: disable=no-self-use,unused-argument
     @post_load