package superset import ( "encoding/json" "net/http" "net/url" "strconv" "fiskerinc.com/modules/logger" "github.com/pkg/errors" ) func GetEmbeddableDashboards(accToken string) (embeddableDashboards []EmbeddableDashboard, err error) { publishedDashboards, err := getPublishedDashboards(accToken) if err != nil { return nil, err } embeddableDashboards = make([]EmbeddableDashboard, 0, len(publishedDashboards)) for _, dashboard := range publishedDashboards { tempId, err := getDashboardsEmbeddedID(dashboard.ID, accToken) // If one of the dashboards gets an error, that could be fine, as long as not all of them do // The dashboard failed to have embedding data on it if err != nil || tempId == "" { continue } embeddableDashboards = append(embeddableDashboards, EmbeddableDashboard{Title: dashboard.DashboardTitle, EmbeddingId: tempId}) } return embeddableDashboards, nil } func getPublishedDashboards(accToken string) (publishedDashboard []publishedDashboard, err error) { // Host already has the /api/v1 targetURL, err := url.JoinPath(host, "dashboard") if err != nil { return nil, errors.WithStack(err) } // ulr.JoinPath with url escape the ? // Filter that published == true targetURL += "/?q=%7B%0A%20%20%22filters%22%3A%20%5B%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22col%22%3A%20%22published%22%2C%0A%20%20%20%20%20%20%22opr%22%3A%20%22eq%22%2C%0A%20%20%20%20%20%20%22value%22%3A%20true%0A%20%20%20%20%7D%0A%20%20%5D%0A%7D" req, err := http.NewRequest("GET", targetURL, nil) if err != nil { return nil, errors.WithStack(err) } req.Header.Set("Accept", "application/json") req.Header.Add("Authorization", "Bearer "+accToken) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, errors.WithStack(err) } defer resp.Body.Close() if resp.StatusCode == 404 { logger.Warn().Msgf("404 while trying to access superset api, code: %s. Trying to get published dashboards\n", resp.Status) } else if resp.StatusCode >= 300 { logger.Error().Msgf("Failed to access superset api, code: %s. Trying to get published dashboards\n", resp.Status) return nil, errors.New("failed to access superset api") } var dashboardResponse getDashboardResponse err = json.NewDecoder(resp.Body).Decode(&dashboardResponse) if err != nil { return nil, errors.WithStack(err) } publishedDashboard = dashboardResponse.Result return } func getDashboardsEmbeddedID(dashboardId int, accToken string) (embeddedId string, err error) { targetURL, err := url.JoinPath(host, "dashboard/", strconv.Itoa(dashboardId), "embedded") if err != nil { return "", errors.WithStack(err) } req, err := http.NewRequest("GET", targetURL, nil) if err != nil { return "", errors.WithStack(err) } req.Header.Set("Accept", "application/json") req.Header.Add("Authorization", "Bearer "+accToken) resp, err := http.DefaultClient.Do(req) if err != nil { return "", errors.WithStack(err) } defer resp.Body.Close() if resp.StatusCode == 404 { logger.Warn().Msgf("Superset dashboard id %s is public, but is not embedable", embeddedId) return "", errors.New("failed to get embedable id") } else if resp.StatusCode >= 300 { logger.Error().Msgf("Failed to access superset api, code: %s. Trying to get embeded dashboard id\n", resp.Status) return "", errors.New("failed to access superset api") } var embeddedResponse getEmbeddedDashboardInfoResponse err = json.NewDecoder(resp.Body).Decode(&embeddedResponse) if err != nil { return "", errors.WithStack(err) } return embeddedResponse.Result.UUID, nil } type getDashboardResponse struct { Count int `json:"count"` Ids []int `json:"ids"` Result []publishedDashboard `json:"result"` } type publishedDashboard struct { DashboardTitle string `json:"dashboard_title"` ID int `json:"id"` } type getEmbeddedDashboardInfoResponse struct { Result struct { UUID string `json:"uuid"` } `json:"result"` } type EmbeddableDashboard struct { Title string `json:"title"` EmbeddingId string `json:"embedded_id"` }