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:12:59 UTC

[superset] branch get-dashboard-by-slug created (now 9b44b92)

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

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


      at 9b44b92  fix(dashboard): accept slug in place of id in url

This branch includes the following new commits:

     new 8ab7a38  refactor out id_or_slug filter logic
     new 9b44b92  fix(dashboard): accept slug in place of id in url

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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

Posted by su...@apache.org.
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


[superset] 01/02: refactor out id_or_slug filter logic

Posted by su...@apache.org.
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 8ab7a38436a0dc32aa467041a7466cf64a262819
Author: David Aaron Suddjian <aa...@gmail.com>
AuthorDate: Thu Feb 25 08:19:56 2021 -0800

    refactor out id_or_slug filter logic
---
 superset/models/dashboard.py | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/superset/models/dashboard.py b/superset/models/dashboard.py
index f827cd4..76b30ad 100644
--- a/superset/models/dashboard.py
+++ b/superset/models/dashboard.py
@@ -42,6 +42,7 @@ from sqlalchemy.orm import relationship, sessionmaker, subqueryload
 from sqlalchemy.orm.mapper import Mapper
 from sqlalchemy.orm.session import object_session
 from sqlalchemy.sql import join, select
+from sqlalchemy.sql.elements import BinaryExpression
 
 from superset import app, ConnectorRegistry, db, is_feature_enabled, security_manager
 from superset.connectors.base.models import BaseDatasource
@@ -359,14 +360,16 @@ class Dashboard(  # pylint: disable=too-many-instance-attributes
         )
 
     @classmethod
-    def get(cls, id_or_slug: str) -> Dashboard:
-        session = db.session()
-        qry = session.query(Dashboard)
+    def id_or_slug_filter(cls, id_or_slug: str) -> BinaryExpression:
         if id_or_slug.isdigit():
-            qry = qry.filter_by(id=int(id_or_slug))
+            return Dashboard.id == int(id_or_slug)
         else:
-            qry = qry.filter_by(slug=id_or_slug)
+            return Dashboard.slug == id_or_slug
 
+    @classmethod
+    def get(cls, id_or_slug: str) -> Dashboard:
+        session = db.session()
+        qry = session.query(Dashboard).filter(Dashboard.id_or_slug_filter(id_or_slug))
         return qry.one_or_none()