mirror of https://github.com/grafana/grafana.git
Public Dashboards: Adds template variable validation for pubdash on the backend (#52566)
Validates template variables for pubdash on the backend when saving a public dashboard
This commit is contained in:
parent
9ef29bb5c3
commit
cf86c696e0
|
|
@ -126,6 +126,7 @@ func (api *Api) SavePublicDashboardConfig(c *models.ReqContext) response.Respons
|
||||||
PublicDashboard: pubdash,
|
PublicDashboard: pubdash,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save the public dashboard
|
||||||
pubdash, err := api.PublicDashboardService.SavePublicDashboardConfig(c.Req.Context(), &dto)
|
pubdash, err := api.PublicDashboardService.SavePublicDashboardConfig(c.Req.Context(), &dto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleDashboardErr(http.StatusInternalServerError, "Failed to save public dashboard configuration", err)
|
return handleDashboardErr(http.StatusInternalServerError, "Failed to save public dashboard configuration", err)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,22 @@ func ProvideStore(sqlStore *sqlstore.SQLStore) *PublicDashboardStoreImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *PublicDashboardStoreImpl) GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error) {
|
||||||
|
dashboard := &models.Dashboard{Uid: dashboardUid}
|
||||||
|
err := d.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
has, err := sess.Get(dashboard)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !has {
|
||||||
|
return ErrPublicDashboardNotFound
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return dashboard, err
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieves public dashboard configuration
|
// Retrieves public dashboard configuration
|
||||||
func (d *PublicDashboardStoreImpl) GetPublicDashboard(ctx context.Context, accessToken string) (*PublicDashboard, *models.Dashboard, error) {
|
func (d *PublicDashboardStoreImpl) GetPublicDashboard(ctx context.Context, accessToken string) (*PublicDashboard, *models.Dashboard, error) {
|
||||||
if accessToken == "" {
|
if accessToken == "" {
|
||||||
|
|
@ -58,17 +74,7 @@ func (d *PublicDashboardStoreImpl) GetPublicDashboard(ctx context.Context, acces
|
||||||
}
|
}
|
||||||
|
|
||||||
// find dashboard
|
// find dashboard
|
||||||
dashRes := &models.Dashboard{OrgId: pdRes.OrgId, Uid: pdRes.DashboardUid}
|
dashRes, err := d.GetDashboard(ctx, pdRes.DashboardUid)
|
||||||
err = d.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
has, err := sess.Get(dashRes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !has {
|
|
||||||
return ErrPublicDashboardNotFound
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,29 @@ var DefaultTimeSettings, _ = simplejson.NewJson([]byte(`{}`))
|
||||||
// Default time to pass in with seconds rounded
|
// Default time to pass in with seconds rounded
|
||||||
var DefaultTime = time.Now().UTC().Round(time.Second)
|
var DefaultTime = time.Now().UTC().Round(time.Second)
|
||||||
|
|
||||||
|
func TestIntegrationGetDashboard(t *testing.T) {
|
||||||
|
var sqlStore *sqlstore.SQLStore
|
||||||
|
var dashboardStore *dashboardsDB.DashboardStore
|
||||||
|
var publicdashboardStore *PublicDashboardStoreImpl
|
||||||
|
var savedDashboard *models.Dashboard
|
||||||
|
|
||||||
|
setup := func() {
|
||||||
|
sqlStore = sqlstore.InitTestDB(t)
|
||||||
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore)
|
||||||
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("GetDashboard can get original dashboard by uid", func(t *testing.T) {
|
||||||
|
setup()
|
||||||
|
|
||||||
|
dashboard, err := publicdashboardStore.GetDashboard(context.Background(), savedDashboard.Uid)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, savedDashboard.Uid, dashboard.Uid)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// GetPublicDashboard
|
// GetPublicDashboard
|
||||||
func TestIntegrationGetPublicDashboard(t *testing.T) {
|
func TestIntegrationGetPublicDashboard(t *testing.T) {
|
||||||
var sqlStore *sqlstore.SQLStore
|
var sqlStore *sqlstore.SQLStore
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,10 @@ var (
|
||||||
Reason: "No Uid for public dashboard specified",
|
Reason: "No Uid for public dashboard specified",
|
||||||
StatusCode: 400,
|
StatusCode: 400,
|
||||||
}
|
}
|
||||||
|
ErrPublicDashboardHasTemplateVariables = PublicDashboardErr{
|
||||||
|
Reason: "Public dashboard has template variables",
|
||||||
|
StatusCode: 422,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type PublicDashboard struct {
|
type PublicDashboard struct {
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,29 @@ func (_m *FakePublicDashboardService) BuildPublicDashboardMetricRequest(ctx cont
|
||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDashboard provides a mock function with given fields: ctx, dashboardUid
|
||||||
|
func (_m *FakePublicDashboardService) GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error) {
|
||||||
|
ret := _m.Called(ctx, dashboardUid)
|
||||||
|
|
||||||
|
var r0 *models.Dashboard
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, string) *models.Dashboard); ok {
|
||||||
|
r0 = rf(ctx, dashboardUid)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*models.Dashboard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||||
|
r1 = rf(ctx, dashboardUid)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetPublicDashboard provides a mock function with given fields: ctx, accessToken
|
// GetPublicDashboard provides a mock function with given fields: ctx, accessToken
|
||||||
func (_m *FakePublicDashboardService) GetPublicDashboard(ctx context.Context, accessToken string) (*models.Dashboard, error) {
|
func (_m *FakePublicDashboardService) GetPublicDashboard(ctx context.Context, accessToken string) (*models.Dashboard, error) {
|
||||||
ret := _m.Called(ctx, accessToken)
|
ret := _m.Called(ctx, accessToken)
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ package publicdashboards
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
models "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
models "github.com/grafana/grafana/pkg/models"
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
pkgmodels "github.com/grafana/grafana/pkg/models"
|
publicdashboardsmodels "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
|
||||||
testing "testing"
|
testing "testing"
|
||||||
)
|
)
|
||||||
|
|
@ -39,25 +39,48 @@ func (_m *FakePublicDashboardStore) GenerateNewPublicDashboardUid(ctx context.Co
|
||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDashboard provides a mock function with given fields: ctx, dashboardUid
|
||||||
|
func (_m *FakePublicDashboardStore) GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error) {
|
||||||
|
ret := _m.Called(ctx, dashboardUid)
|
||||||
|
|
||||||
|
var r0 *models.Dashboard
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, string) *models.Dashboard); ok {
|
||||||
|
r0 = rf(ctx, dashboardUid)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*models.Dashboard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||||
|
r1 = rf(ctx, dashboardUid)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetPublicDashboard provides a mock function with given fields: ctx, accessToken
|
// GetPublicDashboard provides a mock function with given fields: ctx, accessToken
|
||||||
func (_m *FakePublicDashboardStore) GetPublicDashboard(ctx context.Context, accessToken string) (*models.PublicDashboard, *pkgmodels.Dashboard, error) {
|
func (_m *FakePublicDashboardStore) GetPublicDashboard(ctx context.Context, accessToken string) (*publicdashboardsmodels.PublicDashboard, *models.Dashboard, error) {
|
||||||
ret := _m.Called(ctx, accessToken)
|
ret := _m.Called(ctx, accessToken)
|
||||||
|
|
||||||
var r0 *models.PublicDashboard
|
var r0 *publicdashboardsmodels.PublicDashboard
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, string) *models.PublicDashboard); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, string) *publicdashboardsmodels.PublicDashboard); ok {
|
||||||
r0 = rf(ctx, accessToken)
|
r0 = rf(ctx, accessToken)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).(*models.PublicDashboard)
|
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r1 *pkgmodels.Dashboard
|
var r1 *models.Dashboard
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, string) *pkgmodels.Dashboard); ok {
|
if rf, ok := ret.Get(1).(func(context.Context, string) *models.Dashboard); ok {
|
||||||
r1 = rf(ctx, accessToken)
|
r1 = rf(ctx, accessToken)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(1) != nil {
|
if ret.Get(1) != nil {
|
||||||
r1 = ret.Get(1).(*pkgmodels.Dashboard)
|
r1 = ret.Get(1).(*models.Dashboard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,15 +95,15 @@ func (_m *FakePublicDashboardStore) GetPublicDashboard(ctx context.Context, acce
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublicDashboardConfig provides a mock function with given fields: ctx, orgId, dashboardUid
|
// GetPublicDashboardConfig provides a mock function with given fields: ctx, orgId, dashboardUid
|
||||||
func (_m *FakePublicDashboardStore) GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) {
|
func (_m *FakePublicDashboardStore) GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*publicdashboardsmodels.PublicDashboard, error) {
|
||||||
ret := _m.Called(ctx, orgId, dashboardUid)
|
ret := _m.Called(ctx, orgId, dashboardUid)
|
||||||
|
|
||||||
var r0 *models.PublicDashboard
|
var r0 *publicdashboardsmodels.PublicDashboard
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *models.PublicDashboard); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *publicdashboardsmodels.PublicDashboard); ok {
|
||||||
r0 = rf(ctx, orgId, dashboardUid)
|
r0 = rf(ctx, orgId, dashboardUid)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).(*models.PublicDashboard)
|
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,20 +139,20 @@ func (_m *FakePublicDashboardStore) PublicDashboardEnabled(ctx context.Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SavePublicDashboardConfig provides a mock function with given fields: ctx, cmd
|
// SavePublicDashboardConfig provides a mock function with given fields: ctx, cmd
|
||||||
func (_m *FakePublicDashboardStore) SavePublicDashboardConfig(ctx context.Context, cmd models.SavePublicDashboardConfigCommand) (*models.PublicDashboard, error) {
|
func (_m *FakePublicDashboardStore) SavePublicDashboardConfig(ctx context.Context, cmd publicdashboardsmodels.SavePublicDashboardConfigCommand) (*publicdashboardsmodels.PublicDashboard, error) {
|
||||||
ret := _m.Called(ctx, cmd)
|
ret := _m.Called(ctx, cmd)
|
||||||
|
|
||||||
var r0 *models.PublicDashboard
|
var r0 *publicdashboardsmodels.PublicDashboard
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, models.SavePublicDashboardConfigCommand) *models.PublicDashboard); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, publicdashboardsmodels.SavePublicDashboardConfigCommand) *publicdashboardsmodels.PublicDashboard); ok {
|
||||||
r0 = rf(ctx, cmd)
|
r0 = rf(ctx, cmd)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).(*models.PublicDashboard)
|
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, models.SavePublicDashboardConfigCommand) error); ok {
|
if rf, ok := ret.Get(1).(func(context.Context, publicdashboardsmodels.SavePublicDashboardConfigCommand) error); ok {
|
||||||
r1 = rf(ctx, cmd)
|
r1 = rf(ctx, cmd)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
|
|
@ -139,11 +162,11 @@ func (_m *FakePublicDashboardStore) SavePublicDashboardConfig(ctx context.Contex
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePublicDashboardConfig provides a mock function with given fields: ctx, cmd
|
// UpdatePublicDashboardConfig provides a mock function with given fields: ctx, cmd
|
||||||
func (_m *FakePublicDashboardStore) UpdatePublicDashboardConfig(ctx context.Context, cmd models.SavePublicDashboardConfigCommand) error {
|
func (_m *FakePublicDashboardStore) UpdatePublicDashboardConfig(ctx context.Context, cmd publicdashboardsmodels.SavePublicDashboardConfigCommand) error {
|
||||||
ret := _m.Called(ctx, cmd)
|
ret := _m.Called(ctx, cmd)
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, models.SavePublicDashboardConfigCommand) error); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, publicdashboardsmodels.SavePublicDashboardConfigCommand) error); ok {
|
||||||
r0 = rf(ctx, cmd)
|
r0 = rf(ctx, cmd)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
type Service interface {
|
type Service interface {
|
||||||
BuildAnonymousUser(ctx context.Context, dashboard *models.Dashboard) (*models.SignedInUser, error)
|
BuildAnonymousUser(ctx context.Context, dashboard *models.Dashboard) (*models.SignedInUser, error)
|
||||||
GetPublicDashboard(ctx context.Context, accessToken string) (*models.Dashboard, error)
|
GetPublicDashboard(ctx context.Context, accessToken string) (*models.Dashboard, error)
|
||||||
|
GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error)
|
||||||
GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||||
SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error)
|
SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error)
|
||||||
BuildPublicDashboardMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64) (dtos.MetricRequest, error)
|
BuildPublicDashboardMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64) (dtos.MetricRequest, error)
|
||||||
|
|
@ -23,6 +24,7 @@ type Service interface {
|
||||||
//go:generate mockery --name Store --structname FakePublicDashboardStore --inpackage --filename public_dashboard_store_mock.go
|
//go:generate mockery --name Store --structname FakePublicDashboardStore --inpackage --filename public_dashboard_store_mock.go
|
||||||
type Store interface {
|
type Store interface {
|
||||||
GetPublicDashboard(ctx context.Context, accessToken string) (*PublicDashboard, *models.Dashboard, error)
|
GetPublicDashboard(ctx context.Context, accessToken string) (*PublicDashboard, *models.Dashboard, error)
|
||||||
|
GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error)
|
||||||
GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||||
GenerateNewPublicDashboardUid(ctx context.Context) (string, error)
|
GenerateNewPublicDashboardUid(ctx context.Context) (string, error)
|
||||||
SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) (*PublicDashboard, error)
|
SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) (*PublicDashboard, error)
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ import (
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -42,6 +42,16 @@ func ProvideService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pd *PublicDashboardServiceImpl) GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error) {
|
||||||
|
dashboard, err := pd.store.GetDashboard(ctx, dashboardUid)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dashboard, err
|
||||||
|
}
|
||||||
|
|
||||||
// Gets public dashboard via access token
|
// Gets public dashboard via access token
|
||||||
func (pd *PublicDashboardServiceImpl) GetPublicDashboard(ctx context.Context, accessToken string) (*models.Dashboard, error) {
|
func (pd *PublicDashboardServiceImpl) GetPublicDashboard(ctx context.Context, accessToken string) (*models.Dashboard, error) {
|
||||||
pubdash, d, err := pd.store.GetPublicDashboard(ctx, accessToken)
|
pubdash, d, err := pd.store.GetPublicDashboard(ctx, accessToken)
|
||||||
|
|
@ -78,8 +88,13 @@ func (pd *PublicDashboardServiceImpl) GetPublicDashboardConfig(ctx context.Conte
|
||||||
// SavePublicDashboardConfig is a helper method to persist the sharing config
|
// SavePublicDashboardConfig is a helper method to persist the sharing config
|
||||||
// to the database. It handles validations for sharing config and persistence
|
// to the database. It handles validations for sharing config and persistence
|
||||||
func (pd *PublicDashboardServiceImpl) SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error) {
|
func (pd *PublicDashboardServiceImpl) SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error) {
|
||||||
if len(dto.DashboardUid) == 0 {
|
dashboard, err := pd.GetDashboard(ctx, dto.DashboardUid)
|
||||||
return nil, dashboards.ErrDashboardIdentifierNotSet
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = validation.ValidateSavePublicDashboard(dto, dashboard)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// set default value for time settings
|
// set default value for time settings
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||||
sqlStore := sqlstore.InitTestDB(t)
|
sqlStore := sqlstore.InitTestDB(t)
|
||||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||||
|
|
||||||
service := &PublicDashboardServiceImpl{
|
service := &PublicDashboardServiceImpl{
|
||||||
log: log.New("test.logger"),
|
log: log.New("test.logger"),
|
||||||
|
|
@ -164,7 +164,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||||
sqlStore := sqlstore.InitTestDB(t)
|
sqlStore := sqlstore.InitTestDB(t)
|
||||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||||
|
|
||||||
service := &PublicDashboardServiceImpl{
|
service := &PublicDashboardServiceImpl{
|
||||||
log: log.New("test.logger"),
|
log: log.New("test.logger"),
|
||||||
|
|
@ -190,7 +190,32 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||||
assert.Equal(t, defaultPubdashTimeSettings, pubdash.TimeSettings)
|
assert.Equal(t, defaultPubdashTimeSettings, pubdash.TimeSettings)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("PLACEHOLDER - dashboard with template variables cannot be saved", func(t *testing.T) {})
|
t.Run("Validate pubdash whose dashboard has template variables returns error", func(t *testing.T) {
|
||||||
|
sqlStore := sqlstore.InitTestDB(t)
|
||||||
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
||||||
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
|
templateVars := make([]map[string]interface{}, 1)
|
||||||
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, templateVars)
|
||||||
|
|
||||||
|
service := &PublicDashboardServiceImpl{
|
||||||
|
log: log.New("test.logger"),
|
||||||
|
store: publicdashboardStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
dto := &SavePublicDashboardConfigDTO{
|
||||||
|
DashboardUid: dashboard.Uid,
|
||||||
|
OrgId: dashboard.OrgId,
|
||||||
|
UserId: 7,
|
||||||
|
PublicDashboard: &PublicDashboard{
|
||||||
|
IsEnabled: true,
|
||||||
|
DashboardUid: "NOTTHESAME",
|
||||||
|
OrgId: 9999999,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := service.SavePublicDashboardConfig(context.Background(), dto)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdatePublicDashboard(t *testing.T) {
|
func TestUpdatePublicDashboard(t *testing.T) {
|
||||||
|
|
@ -198,7 +223,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||||
sqlStore := sqlstore.InitTestDB(t)
|
sqlStore := sqlstore.InitTestDB(t)
|
||||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||||
|
|
||||||
service := &PublicDashboardServiceImpl{
|
service := &PublicDashboardServiceImpl{
|
||||||
log: log.New("test.logger"),
|
log: log.New("test.logger"),
|
||||||
|
|
@ -265,7 +290,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||||
sqlStore := sqlstore.InitTestDB(t)
|
sqlStore := sqlstore.InitTestDB(t)
|
||||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||||
|
|
||||||
service := &PublicDashboardServiceImpl{
|
service := &PublicDashboardServiceImpl{
|
||||||
log: log.New("test.logger"),
|
log: log.New("test.logger"),
|
||||||
|
|
@ -323,7 +348,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||||
func TestBuildAnonymousUser(t *testing.T) {
|
func TestBuildAnonymousUser(t *testing.T) {
|
||||||
sqlStore := sqlstore.InitTestDB(t)
|
sqlStore := sqlstore.InitTestDB(t)
|
||||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
service := &PublicDashboardServiceImpl{
|
service := &PublicDashboardServiceImpl{
|
||||||
log: log.New("test.logger"),
|
log: log.New("test.logger"),
|
||||||
|
|
@ -346,8 +371,8 @@ func TestBuildPublicDashboardMetricRequest(t *testing.T) {
|
||||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
|
|
||||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||||
nonPublicDashboard := insertTestDashboard(t, dashboardStore, "testNonPublicDashie", 1, 0, true)
|
nonPublicDashboard := insertTestDashboard(t, dashboardStore, "testNonPublicDashie", 1, 0, true, []map[string]interface{}{})
|
||||||
|
|
||||||
service := &PublicDashboardServiceImpl{
|
service := &PublicDashboardServiceImpl{
|
||||||
log: log.New("test.logger"),
|
log: log.New("test.logger"),
|
||||||
|
|
@ -441,7 +466,7 @@ func TestBuildPublicDashboardMetricRequest(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertTestDashboard(t *testing.T, dashboardStore *dashboardsDB.DashboardStore, title string, orgId int64,
|
func insertTestDashboard(t *testing.T, dashboardStore *dashboardsDB.DashboardStore, title string, orgId int64,
|
||||||
folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard {
|
folderId int64, isFolder bool, templateVars []map[string]interface{}, tags ...interface{}) *models.Dashboard {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
cmd := models.SaveDashboardCommand{
|
cmd := models.SaveDashboardCommand{
|
||||||
OrgId: orgId,
|
OrgId: orgId,
|
||||||
|
|
@ -490,6 +515,9 @@ func insertTestDashboard(t *testing.T, dashboardStore *dashboardsDB.DashboardSto
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"templating": map[string]interface{}{
|
||||||
|
"list": templateVars,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
dash, err := dashboardStore.SaveDashboard(cmd)
|
dash, err := dashboardStore.SaveDashboard(cmd)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package validation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
publicdashboardModels "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateSavePublicDashboard(t *testing.T) {
|
||||||
|
t.Run("Returns validation error when dto has no dashboard uid", func(t *testing.T) {
|
||||||
|
dashboard := models.NewDashboard("dashboardTitle")
|
||||||
|
dto := &publicdashboardModels.SavePublicDashboardConfigDTO{DashboardUid: "", OrgId: 1, UserId: 1, PublicDashboard: nil}
|
||||||
|
|
||||||
|
err := ValidateSavePublicDashboard(dto, dashboard)
|
||||||
|
require.ErrorContains(t, err, "Unique identifier needed to be able to get a dashboard")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Returns no validation error when dto has dashboard uid", func(t *testing.T) {
|
||||||
|
dashboard := models.NewDashboard("dashboardTitle")
|
||||||
|
dto := &publicdashboardModels.SavePublicDashboardConfigDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: nil}
|
||||||
|
|
||||||
|
err := ValidateSavePublicDashboard(dto, dashboard)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Returns validation error when dashboard has template variables", func(t *testing.T) {
|
||||||
|
templateVars := []byte(`{
|
||||||
|
"templating": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "templateVariableName"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
dashboardData, _ := simplejson.NewJson(templateVars)
|
||||||
|
dashboard := models.NewDashboardFromJson(dashboardData)
|
||||||
|
dto := &publicdashboardModels.SavePublicDashboardConfigDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: nil}
|
||||||
|
|
||||||
|
err := ValidateSavePublicDashboard(dto, dashboard)
|
||||||
|
require.ErrorContains(t, err, "Public dashboard has template variables")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Returns no validation error when dashboard has no template variables", func(t *testing.T) {
|
||||||
|
templateVars := []byte(`{
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
dashboardData, _ := simplejson.NewJson(templateVars)
|
||||||
|
dashboard := models.NewDashboardFromJson(dashboardData)
|
||||||
|
dto := &publicdashboardModels.SavePublicDashboardConfigDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: nil}
|
||||||
|
|
||||||
|
err := ValidateSavePublicDashboard(dto, dashboard)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package validation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
|
publicDashboardModels "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ValidateSavePublicDashboard(dto *publicDashboardModels.SavePublicDashboardConfigDTO, dashboard *models.Dashboard) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(dto.DashboardUid) == 0 {
|
||||||
|
return dashboards.ErrDashboardIdentifierNotSet
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasTemplateVariables(dashboard) {
|
||||||
|
return publicDashboardModels.ErrPublicDashboardHasTemplateVariables
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasTemplateVariables(dashboard *models.Dashboard) bool {
|
||||||
|
templateVariables := dashboard.Data.Get("templating").Get("list").MustArray()
|
||||||
|
|
||||||
|
return len(templateVariables) > 0
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue