2022-06-02 18:27:23 -08:00
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2022-06-22 13:58:52 -08:00
|
|
|
"fmt"
|
|
|
|
|
"time"
|
2022-06-02 18:27:23 -08:00
|
|
|
|
2022-06-30 20:55:33 +02:00
|
|
|
"github.com/google/uuid"
|
2022-06-13 17:23:56 -06:00
|
|
|
"github.com/grafana/grafana/pkg/api/dtos"
|
2022-06-22 13:58:52 -08:00
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
2022-06-02 18:27:23 -08:00
|
|
|
"github.com/grafana/grafana/pkg/models"
|
|
|
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
2022-07-06 12:42:39 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
2022-06-02 18:27:23 -08:00
|
|
|
)
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
// Gets public dashboard via access token
|
|
|
|
|
func (dr *DashboardServiceImpl) GetPublicDashboard(ctx context.Context, accessToken string) (*models.Dashboard, error) {
|
|
|
|
|
pubdash, d, err := dr.dashboardStore.GetPublicDashboard(ctx, accessToken)
|
2022-06-02 18:27:23 -08:00
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
if pubdash == nil || d == nil {
|
2022-06-30 09:31:54 -04:00
|
|
|
return nil, dashboards.ErrPublicDashboardNotFound
|
2022-06-02 18:27:23 -08:00
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
if !pubdash.IsEnabled {
|
2022-06-30 09:31:54 -04:00
|
|
|
return nil, dashboards.ErrPublicDashboardNotFound
|
2022-06-02 18:27:23 -08:00
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
ts := pubdash.BuildTimeSettings(d)
|
|
|
|
|
d.Data.SetPath([]string{"time", "from"}, ts.From)
|
|
|
|
|
d.Data.SetPath([]string{"time", "to"}, ts.To)
|
2022-06-02 18:27:23 -08:00
|
|
|
|
|
|
|
|
return d, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetPublicDashboardConfig is a helper method to retrieve the public dashboard configuration for a given dashboard from the database
|
2022-06-22 13:58:52 -08:00
|
|
|
func (dr *DashboardServiceImpl) GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) {
|
|
|
|
|
pdc, err := dr.dashboardStore.GetPublicDashboardConfig(ctx, orgId, dashboardUid)
|
2022-06-02 18:27:23 -08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pdc, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SavePublicDashboardConfig is a helper method to persist the sharing config
|
|
|
|
|
// to the database. It handles validations for sharing config and persistence
|
2022-06-22 13:58:52 -08:00
|
|
|
func (dr *DashboardServiceImpl) SavePublicDashboardConfig(ctx context.Context, dto *dashboards.SavePublicDashboardConfigDTO) (*models.PublicDashboard, error) {
|
|
|
|
|
if len(dto.DashboardUid) == 0 {
|
2022-06-30 09:31:54 -04:00
|
|
|
return nil, dashboards.ErrDashboardIdentifierNotSet
|
2022-06-22 13:58:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set default value for time settings
|
|
|
|
|
if dto.PublicDashboard.TimeSettings == nil {
|
2022-06-30 18:30:01 -03:00
|
|
|
dto.PublicDashboard.TimeSettings = simplejson.New()
|
2022-06-02 18:27:23 -08:00
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
if dto.PublicDashboard.Uid == "" {
|
|
|
|
|
return dr.savePublicDashboardConfig(ctx, dto)
|
|
|
|
|
}
|
2022-06-02 18:27:23 -08:00
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
return dr.updatePublicDashboardConfig(ctx, dto)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (dr *DashboardServiceImpl) savePublicDashboardConfig(ctx context.Context, dto *dashboards.SavePublicDashboardConfigDTO) (*models.PublicDashboard, error) {
|
|
|
|
|
uid, err := dr.dashboardStore.GenerateNewPublicDashboardUid(ctx)
|
2022-06-02 18:27:23 -08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
accessToken, err := GenerateAccessToken()
|
2022-06-13 17:23:56 -06:00
|
|
|
if err != nil {
|
2022-06-22 13:58:52 -08:00
|
|
|
return nil, err
|
2022-06-13 17:23:56 -06:00
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
cmd := models.SavePublicDashboardConfigCommand{
|
|
|
|
|
DashboardUid: dto.DashboardUid,
|
|
|
|
|
OrgId: dto.OrgId,
|
|
|
|
|
PublicDashboard: models.PublicDashboard{
|
|
|
|
|
Uid: uid,
|
|
|
|
|
DashboardUid: dto.DashboardUid,
|
|
|
|
|
OrgId: dto.OrgId,
|
|
|
|
|
IsEnabled: dto.PublicDashboard.IsEnabled,
|
|
|
|
|
TimeSettings: dto.PublicDashboard.TimeSettings,
|
|
|
|
|
CreatedBy: dto.UserId,
|
|
|
|
|
CreatedAt: time.Now(),
|
|
|
|
|
AccessToken: accessToken,
|
|
|
|
|
},
|
2022-06-13 17:23:56 -06:00
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
return dr.dashboardStore.SavePublicDashboardConfig(ctx, cmd)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (dr *DashboardServiceImpl) updatePublicDashboardConfig(ctx context.Context, dto *dashboards.SavePublicDashboardConfigDTO) (*models.PublicDashboard, error) {
|
|
|
|
|
cmd := models.SavePublicDashboardConfigCommand{
|
|
|
|
|
PublicDashboard: models.PublicDashboard{
|
|
|
|
|
Uid: dto.PublicDashboard.Uid,
|
|
|
|
|
IsEnabled: dto.PublicDashboard.IsEnabled,
|
|
|
|
|
TimeSettings: dto.PublicDashboard.TimeSettings,
|
|
|
|
|
UpdatedBy: dto.UserId,
|
|
|
|
|
UpdatedAt: time.Now(),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := dr.dashboardStore.UpdatePublicDashboardConfig(ctx, cmd)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2022-06-13 17:23:56 -06:00
|
|
|
}
|
2022-06-22 13:58:52 -08:00
|
|
|
|
|
|
|
|
publicDashboard, err := dr.dashboardStore.GetPublicDashboardConfig(ctx, dto.OrgId, dto.DashboardUid)
|
2022-06-13 17:23:56 -06:00
|
|
|
if err != nil {
|
2022-06-22 13:58:52 -08:00
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return publicDashboard, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BuildPublicDashboardMetricRequest merges public dashboard parameters with
|
|
|
|
|
// dashboard and returns a metrics request to be sent to query backend
|
|
|
|
|
func (dr *DashboardServiceImpl) BuildPublicDashboardMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *models.PublicDashboard, panelId int64) (dtos.MetricRequest, error) {
|
|
|
|
|
if !publicDashboard.IsEnabled {
|
2022-06-30 09:31:54 -04:00
|
|
|
return dtos.MetricRequest{}, dashboards.ErrPublicDashboardNotFound
|
2022-06-13 17:23:56 -06:00
|
|
|
}
|
|
|
|
|
|
2022-07-06 12:42:39 -06:00
|
|
|
queriesByPanel := models.GroupQueriesByPanelId(dashboard.Data)
|
2022-06-13 17:23:56 -06:00
|
|
|
|
|
|
|
|
if _, ok := queriesByPanel[panelId]; !ok {
|
2022-06-30 09:31:54 -04:00
|
|
|
return dtos.MetricRequest{}, dashboards.ErrPublicDashboardPanelNotFound
|
2022-06-13 17:23:56 -06:00
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
ts := publicDashboard.BuildTimeSettings(dashboard)
|
|
|
|
|
|
2022-06-13 17:23:56 -06:00
|
|
|
return dtos.MetricRequest{
|
2022-06-22 13:58:52 -08:00
|
|
|
From: ts.From,
|
|
|
|
|
To: ts.To,
|
2022-06-13 17:23:56 -06:00
|
|
|
Queries: queriesByPanel[panelId],
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
2022-06-22 13:58:52 -08:00
|
|
|
|
2022-07-06 12:42:39 -06:00
|
|
|
// BuildAnonymousUser creates a user with permissions to read from all datasources used in the dashboard
|
|
|
|
|
func (dr *DashboardServiceImpl) BuildAnonymousUser(ctx context.Context, dashboard *models.Dashboard) (*models.SignedInUser, error) {
|
|
|
|
|
datasourceUids := models.GetUniqueDashboardDatasourceUids(dashboard.Data)
|
|
|
|
|
|
|
|
|
|
// Create a temp user with read-only datasource permissions
|
|
|
|
|
anonymousUser := &models.SignedInUser{OrgId: dashboard.OrgId, Permissions: make(map[int64]map[string][]string)}
|
|
|
|
|
permissions := make(map[string][]string)
|
|
|
|
|
queryScopes := make([]string, 0)
|
|
|
|
|
readScopes := make([]string, 0)
|
|
|
|
|
for _, uid := range datasourceUids {
|
|
|
|
|
queryScopes = append(queryScopes, fmt.Sprintf("datasources:uid:%s", uid))
|
|
|
|
|
readScopes = append(readScopes, fmt.Sprintf("datasources:uid:%s", uid))
|
|
|
|
|
}
|
|
|
|
|
permissions[datasources.ActionQuery] = queryScopes
|
|
|
|
|
permissions[datasources.ActionRead] = readScopes
|
|
|
|
|
anonymousUser.Permissions[dashboard.OrgId] = permissions
|
|
|
|
|
|
|
|
|
|
return anonymousUser, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-22 13:58:52 -08:00
|
|
|
// generates a uuid formatted without dashes to use as access token
|
|
|
|
|
func GenerateAccessToken() (string, error) {
|
2022-06-30 20:55:33 +02:00
|
|
|
token, err := uuid.NewRandom()
|
2022-06-22 13:58:52 -08:00
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-30 20:55:33 +02:00
|
|
|
return fmt.Sprintf("%x", token[:]), nil
|
2022-06-22 13:58:52 -08:00
|
|
|
}
|