public-dashboards: Add log statement when public dashboard enabled or disabled (#54133)

* refactor apis for consistent outputs
* add dashboardUid validation at API layer
* add check for empty dashboardUid on SavePublicDashboard
* remove public dashboard errors from models package.

Co-authored-by: Ezequiel Victorero <evictorero@gmail.com>
This commit is contained in:
Jeff Levin 2022-08-26 11:28:54 -08:00 committed by GitHub
parent b9be2815d3
commit 5cb9fca990
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 215 additions and 148 deletions

View File

@ -125,28 +125,6 @@ var (
StatusCode: 404,
Status: "not-found",
}
ErrPublicDashboardFailedGenerateUniqueUid = DashboardErr{
Reason: "Failed to generate unique public dashboard id",
StatusCode: 500,
}
ErrPublicDashboardFailedGenerateAccesstoken = DashboardErr{
Reason: "Failed to public dashboard access token",
StatusCode: 500,
}
ErrPublicDashboardNotFound = DashboardErr{
Reason: "Public dashboard not found",
StatusCode: 404,
Status: "not-found",
}
ErrPublicDashboardPanelNotFound = DashboardErr{
Reason: "Panel not found in dashboard",
StatusCode: 404,
Status: "not-found",
}
ErrPublicDashboardIdentifierNotSet = DashboardErr{
Reason: "No Uid for public dashboard specified",
StatusCode: 400,
}
ErrFolderNotFound = errors.New("folder not found")
ErrFolderVersionMismatch = errors.New("the folder has been changed by someone else")

View File

@ -120,23 +120,28 @@ func (api *Api) GetPublicDashboardConfig(c *models.ReqContext) response.Response
// Sets public dashboard configuration for dashboard
// POST /api/dashboards/uid/:uid/public-config
func (api *Api) SavePublicDashboardConfig(c *models.ReqContext) response.Response {
// exit if we don't have a valid dashboardUid
dashboardUid := web.Params(c.Req)[":uid"]
if dashboardUid == "" || !util.IsValidShortUID(dashboardUid) {
handleDashboardErr(http.StatusBadRequest, "no dashboardUid", dashboards.ErrDashboardIdentifierNotSet)
}
pubdash := &PublicDashboard{}
if err := web.Bind(c.Req, pubdash); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
// Always set the org id to the current auth session orgId
// Always set the orgID and userID from the session
pubdash.OrgId = c.OrgID
dto := SavePublicDashboardConfigDTO{
OrgId: c.OrgID,
DashboardUid: web.Params(c.Req)[":uid"],
UserId: c.UserID,
OrgId: c.OrgID,
DashboardUid: dashboardUid,
PublicDashboard: pubdash,
}
// Save the public dashboard
pubdash, err := api.PublicDashboardService.SavePublicDashboardConfig(c.Req.Context(), &dto)
pubdash, err := api.PublicDashboardService.SavePublicDashboardConfig(c.Req.Context(), c.SignedInUser, &dto)
if err != nil {
return handleDashboardErr(http.StatusInternalServerError, "Failed to save public dashboard configuration", err)
}

View File

@ -240,7 +240,7 @@ func TestApiSavePublicDashboardConfig(t *testing.T) {
for _, test := range testCases {
t.Run(test.Name, func(t *testing.T) {
service := publicdashboards.NewFakePublicDashboardService(t)
service.On("SavePublicDashboardConfig", mock.Anything, mock.AnythingOfType("*models.SavePublicDashboardConfigDTO")).
service.On("SavePublicDashboardConfig", mock.Anything, mock.Anything, mock.AnythingOfType("*models.SavePublicDashboardConfigDTO")).
Return(&PublicDashboard{IsEnabled: true}, test.SaveDashboardErr)
cfg := setting.NewCfg()
@ -558,7 +558,7 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T)
cfg := setting.NewCfg()
cfg.RBACEnabled = false
service := publicdashboardsService.ProvideService(cfg, store)
pubdash, err := service.SavePublicDashboardConfig(context.Background(), savePubDashboardCmd)
pubdash, err := service.SavePublicDashboardConfig(context.Background(), &user.SignedInUser{}, savePubDashboardCmd)
require.NoError(t, err)
// setup test server

View File

@ -113,6 +113,31 @@ func (d *PublicDashboardStoreImpl) GenerateNewPublicDashboardUid(ctx context.Con
return uid, nil
}
// Retrieves public dashboard configuration by Uid
func (d *PublicDashboardStoreImpl) GetPublicDashboardByUid(ctx context.Context, uid string) (*PublicDashboard, error) {
if uid == "" {
return nil, nil
}
var found bool
pdRes := &PublicDashboard{Uid: uid}
err := d.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
var err error
found, err = sess.Get(pdRes)
return err
})
if err != nil {
return nil, err
}
if !found {
return nil, nil
}
return pdRes, err
}
// Retrieves public dashboard configuration
func (d *PublicDashboardStoreImpl) GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error) {
if dashboardUid == "" {
@ -138,7 +163,11 @@ func (d *PublicDashboardStoreImpl) GetPublicDashboardConfig(ctx context.Context,
}
// Persists public dashboard configuration
func (d *PublicDashboardStoreImpl) SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) (*PublicDashboard, error) {
func (d *PublicDashboardStoreImpl) SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) error {
if cmd.PublicDashboard.DashboardUid == "" {
return dashboards.ErrDashboardIdentifierNotSet
}
err := d.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
_, err := sess.UseBool("is_enabled").Insert(&cmd.PublicDashboard)
if err != nil {
@ -148,11 +177,7 @@ func (d *PublicDashboardStoreImpl) SavePublicDashboardConfig(ctx context.Context
return nil
})
if err != nil {
return nil, err
}
return &cmd.PublicDashboard, nil
return err
}
// updates existing public dashboard configuration

View File

@ -67,7 +67,7 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
t.Run("AccessTokenExists will return true when at least one public dashboard has a matching access token", func(t *testing.T) {
setup()
_, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
IsEnabled: true,
Uid: "abc123",
@ -98,7 +98,7 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
t.Run("PublicDashboardEnabled Will return true when dashboard has at least one enabled public dashboard", func(t *testing.T) {
setup()
_, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
IsEnabled: true,
Uid: "abc123",
@ -120,7 +120,7 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
t.Run("PublicDashboardEnabled will return false when dashboard has public dashboards but they are not enabled", func(t *testing.T) {
setup()
_, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
IsEnabled: false,
Uid: "abc123",
@ -141,7 +141,7 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
t.Run("returns PublicDashboard and Dashboard", func(t *testing.T) {
setup()
pubdash, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
cmd := SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
IsEnabled: true,
Uid: "abc1234",
@ -152,14 +152,16 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
CreatedBy: 7,
AccessToken: "NOTAREALUUID",
},
})
}
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), cmd)
require.NoError(t, err)
pd, d, err := publicdashboardStore.GetPublicDashboard(context.Background(), "NOTAREALUUID")
require.NoError(t, err)
assert.Equal(t, pd, pubdash)
assert.Equal(t, d.Uid, pubdash.DashboardUid)
assert.Equal(t, pd, &cmd.PublicDashboard)
assert.Equal(t, d.Uid, cmd.PublicDashboard.DashboardUid)
})
t.Run("returns ErrPublicDashboardNotFound with empty uid", func(t *testing.T) {
@ -176,7 +178,7 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
t.Run("returns ErrDashboardNotFound when Dashboard not found", func(t *testing.T) {
setup()
_, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
IsEnabled: true,
Uid: "abc1234",
@ -219,10 +221,9 @@ func TestIntegrationGetPublicDashboardConfig(t *testing.T) {
require.Error(t, dashboards.ErrDashboardIdentifierNotSet, err)
})
t.Run("returns isPublic along with public dashboard when exists", func(t *testing.T) {
t.Run("returns along with public dashboard when exists", func(t *testing.T) {
setup()
// insert test public dashboard
resp, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
cmd := SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
IsEnabled: true,
Uid: "pubdash-uid",
@ -232,14 +233,17 @@ func TestIntegrationGetPublicDashboardConfig(t *testing.T) {
CreatedAt: DefaultTime,
CreatedBy: 7,
},
})
}
// insert test public dashboard
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), cmd)
require.NoError(t, err)
// retrieve from db
pubdash, err := publicdashboardStore.GetPublicDashboardConfig(context.Background(), savedDashboard.OrgId, savedDashboard.Uid)
require.NoError(t, err)
assert.True(t, assert.ObjectsAreEqualValues(resp, pubdash))
assert.True(t, assert.ObjectsAreEqual(resp, pubdash))
assert.True(t, assert.ObjectsAreEqualValues(&cmd.PublicDashboard, pubdash))
})
}
@ -261,7 +265,7 @@ func TestIntegrationSavePublicDashboardConfig(t *testing.T) {
t.Run("saves new public dashboard", func(t *testing.T) {
setup()
resp, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
IsEnabled: true,
Uid: "pubdash-uid",
@ -278,9 +282,6 @@ func TestIntegrationSavePublicDashboardConfig(t *testing.T) {
pubdash, err := publicdashboardStore.GetPublicDashboardConfig(context.Background(), savedDashboard.OrgId, savedDashboard.Uid)
require.NoError(t, err)
//verify saved response and queried response are the same
assert.Equal(t, resp, pubdash)
// verify we have a valid uid
assert.True(t, util.IsValidShortUID(pubdash.Uid))
@ -289,6 +290,23 @@ func TestIntegrationSavePublicDashboardConfig(t *testing.T) {
require.NoError(t, err)
assert.False(t, pubdash2.IsEnabled)
})
t.Run("guards from saving without dashboardUid", func(t *testing.T) {
setup()
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
IsEnabled: true,
Uid: "pubdash-uid",
DashboardUid: "",
OrgId: savedDashboard.OrgId,
TimeSettings: DefaultTimeSettings,
CreatedAt: DefaultTime,
CreatedBy: 7,
AccessToken: "NOTAREALUUID",
},
})
assert.Error(t, err, dashboards.ErrDashboardIdentifierNotSet)
})
}
func TestIntegrationUpdatePublicDashboard(t *testing.T) {
@ -310,7 +328,7 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
setup()
pdUid := "asdf1234"
_, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
Uid: pdUid,
DashboardUid: savedDashboard.Uid,
@ -325,7 +343,7 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
// inserting two different public dashboards to test update works and only affect the desired pd by uid
anotherPdUid := "anotherUid"
_, err = publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
err = publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
Uid: anotherPdUid,
DashboardUid: anotherSavedDashboard.Uid,
@ -365,11 +383,11 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
// not updated dashboard shouldn't have changed
pdNotUpdatedRetrieved, err := publicdashboardStore.GetPublicDashboardConfig(context.Background(), anotherSavedDashboard.OrgId, anotherSavedDashboard.Uid)
require.NoError(t, err)
assert.NotEqual(t, updatedPublicDashboard.UpdatedAt, pdNotUpdatedRetrieved.UpdatedAt)
assert.NotEqual(t, updatedPublicDashboard.IsEnabled, pdNotUpdatedRetrieved.IsEnabled)
})
}
func insertTestDashboard(t *testing.T, dashboardStore *dashboardsDB.DashboardStore, title string, orgId int64,
folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard {
t.Helper()

View File

@ -186,13 +186,13 @@ func (_m *FakePublicDashboardService) PublicDashboardEnabled(ctx context.Context
return r0, r1
}
// SavePublicDashboardConfig provides a mock function with given fields: ctx, dto
func (_m *FakePublicDashboardService) SavePublicDashboardConfig(ctx context.Context, dto *publicdashboardsmodels.SavePublicDashboardConfigDTO) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, dto)
// SavePublicDashboardConfig provides a mock function with given fields: ctx, u, dto
func (_m *FakePublicDashboardService) SavePublicDashboardConfig(ctx context.Context, u *user.SignedInUser, dto *publicdashboardsmodels.SavePublicDashboardConfigDTO) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, u, dto)
var r0 *publicdashboardsmodels.PublicDashboard
if rf, ok := ret.Get(0).(func(context.Context, *publicdashboardsmodels.SavePublicDashboardConfigDTO) *publicdashboardsmodels.PublicDashboard); ok {
r0 = rf(ctx, dto)
if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, *publicdashboardsmodels.SavePublicDashboardConfigDTO) *publicdashboardsmodels.PublicDashboard); ok {
r0 = rf(ctx, u, dto)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
@ -200,8 +200,8 @@ func (_m *FakePublicDashboardService) SavePublicDashboardConfig(ctx context.Cont
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *publicdashboardsmodels.SavePublicDashboardConfigDTO) error); ok {
r1 = rf(ctx, dto)
if rf, ok := ret.Get(1).(func(context.Context, *user.SignedInUser, *publicdashboardsmodels.SavePublicDashboardConfigDTO) error); ok {
r1 = rf(ctx, u, dto)
} else {
r1 = ret.Error(1)
}

View File

@ -115,6 +115,29 @@ func (_m *FakePublicDashboardStore) GetPublicDashboard(ctx context.Context, acce
return r0, r1, r2
}
// GetPublicDashboardByUid provides a mock function with given fields: ctx, uid
func (_m *FakePublicDashboardStore) GetPublicDashboardByUid(ctx context.Context, uid string) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, uid)
var r0 *publicdashboardsmodels.PublicDashboard
if rf, ok := ret.Get(0).(func(context.Context, string) *publicdashboardsmodels.PublicDashboard); ok {
r0 = rf(ctx, uid)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, uid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetPublicDashboardConfig provides a mock function with given fields: ctx, orgId, dashboardUid
func (_m *FakePublicDashboardStore) GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
@ -160,26 +183,17 @@ func (_m *FakePublicDashboardStore) PublicDashboardEnabled(ctx context.Context,
}
// SavePublicDashboardConfig provides a mock function with given fields: ctx, cmd
func (_m *FakePublicDashboardStore) SavePublicDashboardConfig(ctx context.Context, cmd publicdashboardsmodels.SavePublicDashboardConfigCommand) (*publicdashboardsmodels.PublicDashboard, error) {
func (_m *FakePublicDashboardStore) SavePublicDashboardConfig(ctx context.Context, cmd publicdashboardsmodels.SavePublicDashboardConfigCommand) error {
ret := _m.Called(ctx, cmd)
var r0 *publicdashboardsmodels.PublicDashboard
if rf, ok := ret.Get(0).(func(context.Context, publicdashboardsmodels.SavePublicDashboardConfigCommand) *publicdashboardsmodels.PublicDashboard); ok {
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, publicdashboardsmodels.SavePublicDashboardConfigCommand) error); ok {
r0 = rf(ctx, cmd)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
}
r0 = ret.Error(0)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, publicdashboardsmodels.SavePublicDashboardConfigCommand) error); ok {
r1 = rf(ctx, cmd)
} else {
r1 = ret.Error(1)
}
return r0, r1
return r0
}
// UpdatePublicDashboardConfig provides a mock function with given fields: ctx, cmd

View File

@ -17,7 +17,7 @@ type Service interface {
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)
SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error)
SavePublicDashboardConfig(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error)
BuildPublicDashboardMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64) (dtos.MetricRequest, error)
PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error)
AccessTokenExists(ctx context.Context, accessToken string) (bool, error)
@ -28,8 +28,9 @@ type Store interface {
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)
GetPublicDashboardByUid(ctx context.Context, uid string) (*PublicDashboard, error)
GenerateNewPublicDashboardUid(ctx context.Context) (string, error)
SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) (*PublicDashboard, error)
SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) error
UpdatePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) error
PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error)
AccessTokenExists(ctx context.Context, accessToken string) (bool, error)

View File

@ -86,11 +86,12 @@ func (pd *PublicDashboardServiceImpl) GetPublicDashboardConfig(ctx context.Conte
// SavePublicDashboardConfig is a helper method to persist the sharing config
// 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, u *user.SignedInUser, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error) {
dashboard, err := pd.GetDashboard(ctx, dto.DashboardUid)
if err != nil {
return nil, err
}
err = validation.ValidateSavePublicDashboard(dto, dashboard)
if err != nil {
return nil, err
@ -101,22 +102,45 @@ func (pd *PublicDashboardServiceImpl) SavePublicDashboardConfig(ctx context.Cont
dto.PublicDashboard.TimeSettings = simplejson.New()
}
if dto.PublicDashboard.Uid == "" {
return pd.savePublicDashboardConfig(ctx, dto)
}
return pd.updatePublicDashboardConfig(ctx, dto)
}
func (pd *PublicDashboardServiceImpl) savePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error) {
uid, err := pd.store.GenerateNewPublicDashboardUid(ctx)
// get existing public dashboard if exists
existingPubdash, err := pd.store.GetPublicDashboardByUid(ctx, dto.PublicDashboard.Uid)
if err != nil {
return nil, err
}
// save changes
var pubdashUid string
if existingPubdash == nil {
pubdashUid, err = pd.savePublicDashboardConfig(ctx, dto)
} else {
pubdashUid, err = pd.updatePublicDashboardConfig(ctx, dto)
}
if err != nil {
return nil, err
}
//Get latest public dashboard to return
newPubdash, err := pd.store.GetPublicDashboardByUid(ctx, pubdashUid)
if err != nil {
return nil, err
}
pd.logIsEnabledChanged(existingPubdash, newPubdash, u)
return newPubdash, err
}
// Called by SavePublicDashboardConfig this handles business logic
// to generate token and calls create at the database layer
func (pd *PublicDashboardServiceImpl) savePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (string, error) {
uid, err := pd.store.GenerateNewPublicDashboardUid(ctx)
if err != nil {
return "", err
}
accessToken, err := GenerateAccessToken()
if err != nil {
return nil, err
return "", err
}
cmd := SavePublicDashboardConfigCommand{
@ -132,10 +156,17 @@ func (pd *PublicDashboardServiceImpl) savePublicDashboardConfig(ctx context.Cont
},
}
return pd.store.SavePublicDashboardConfig(ctx, cmd)
err = pd.store.SavePublicDashboardConfig(ctx, cmd)
if err != nil {
return "", err
}
return uid, nil
}
func (pd *PublicDashboardServiceImpl) updatePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error) {
// Called by SavePublicDashboard this handles business logic for updating a
// dashboard and calls update at the database layer
func (pd *PublicDashboardServiceImpl) updatePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (string, error) {
cmd := SavePublicDashboardConfigCommand{
PublicDashboard: PublicDashboard{
Uid: dto.PublicDashboard.Uid,
@ -146,17 +177,7 @@ func (pd *PublicDashboardServiceImpl) updatePublicDashboardConfig(ctx context.Co
},
}
err := pd.store.UpdatePublicDashboardConfig(ctx, cmd)
if err != nil {
return nil, err
}
publicDashboard, err := pd.store.GetPublicDashboardConfig(ctx, dto.OrgId, dto.DashboardUid)
if err != nil {
return nil, err
}
return publicDashboard, nil
return dto.PublicDashboard.Uid, pd.store.UpdatePublicDashboardConfig(ctx, cmd)
}
// BuildPublicDashboardMetricRequest merges public dashboard parameters with
@ -218,3 +239,23 @@ func GenerateAccessToken() (string, error) {
return fmt.Sprintf("%x", token[:]), nil
}
// Log when PublicDashboard.IsEnabled changed
func (pd *PublicDashboardServiceImpl) logIsEnabledChanged(existingPubdash *PublicDashboard, newPubdash *PublicDashboard, u *user.SignedInUser) {
if publicDashboardIsEnabledChanged(existingPubdash, newPubdash) {
verb := "disabled"
if newPubdash.IsEnabled {
verb = "enabled"
}
pd.log.Info(fmt.Sprintf("Public dashboard %v: dashboardUid: %v, user:%v", verb, newPubdash.Uid, u.Login))
}
}
// Checks to see if PublicDashboard.Isenabled is true on create or changed on update
func publicDashboardIsEnabledChanged(existingPubdash *PublicDashboard, newPubdash *PublicDashboard) bool {
// creating dashboard, enabled true
newDashCreated := existingPubdash == nil && newPubdash.IsEnabled
// updating dashboard, enabled changed
isEnabledChanged := existingPubdash != nil && newPubdash.IsEnabled != existingPubdash.IsEnabled
return newDashCreated || isEnabledChanged
}

View File

@ -6,6 +6,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/user"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
@ -25,6 +26,7 @@ import (
var timeSettings, _ = simplejson.NewJson([]byte(`{"from": "now-12", "to": "now"}`))
var defaultPubdashTimeSettings, _ = simplejson.NewJson([]byte(`{}`))
var dashboardData = simplejson.NewFromAny(map[string]interface{}{"time": map[string]interface{}{"from": "now-8", "to": "now"}})
var SignedInUser = &user.SignedInUser{UserID: 1234, Login: "user@login.com"}
func TestLogPrefix(t *testing.T) {
assert.Equal(t, LogPrefix, "publicdashboards.service")
@ -134,7 +136,7 @@ func TestSavePublicDashboard(t *testing.T) {
},
}
_, err := service.SavePublicDashboardConfig(context.Background(), dto)
_, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
require.NoError(t, err)
pubdash, err := service.GetPublicDashboardConfig(context.Background(), dashboard.OrgId, dashboard.Uid)
@ -177,7 +179,7 @@ func TestSavePublicDashboard(t *testing.T) {
},
}
_, err := service.SavePublicDashboardConfig(context.Background(), dto)
_, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
require.NoError(t, err)
pubdash, err := service.GetPublicDashboardConfig(context.Background(), dashboard.OrgId, dashboard.Uid)
@ -208,7 +210,7 @@ func TestSavePublicDashboard(t *testing.T) {
},
}
_, err := service.SavePublicDashboardConfig(context.Background(), dto)
_, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
require.Error(t, err)
})
}
@ -235,10 +237,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
},
}
_, err := service.SavePublicDashboardConfig(context.Background(), dto)
require.NoError(t, err)
savedPubdash, err := service.GetPublicDashboardConfig(context.Background(), dashboard.OrgId, dashboard.Uid)
savedPubdash, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
require.NoError(t, err)
// attempt to overwrite settings
@ -261,10 +260,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
// Since the dto.PublicDashboard has a uid, this will call
// service.updatePublicDashboardConfig
_, err = service.SavePublicDashboardConfig(context.Background(), dto)
require.NoError(t, err)
updatedPubdash, err := service.GetPublicDashboardConfig(context.Background(), dashboard.OrgId, dashboard.Uid)
updatedPubdash, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
require.NoError(t, err)
// don't get updated
@ -304,10 +300,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
// Since the dto.PublicDashboard has a uid, this will call
// service.updatePublicDashboardConfig
_, err := service.SavePublicDashboardConfig(context.Background(), dto)
require.NoError(t, err)
savedPubdash, err := service.GetPublicDashboardConfig(context.Background(), dashboard.OrgId, dashboard.Uid)
savedPubdash, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
require.NoError(t, err)
// attempt to overwrite settings
@ -327,10 +320,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
},
}
_, err = service.SavePublicDashboardConfig(context.Background(), dto)
require.NoError(t, err)
updatedPubdash, err := service.GetPublicDashboardConfig(context.Background(), dashboard.OrgId, dashboard.Uid)
updatedPubdash, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
require.NoError(t, err)
timeSettings, err := simplejson.NewJson([]byte("{}"))
@ -385,7 +375,7 @@ func TestBuildPublicDashboardMetricRequest(t *testing.T) {
},
}
publicDashboardPD, err := service.SavePublicDashboardConfig(context.Background(), dto)
publicDashboardPD, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
require.NoError(t, err)
nonPublicDto := &SavePublicDashboardConfigDTO{
@ -399,7 +389,7 @@ func TestBuildPublicDashboardMetricRequest(t *testing.T) {
},
}
nonPublicDashboardPD, err := service.SavePublicDashboardConfig(context.Background(), nonPublicDto)
nonPublicDashboardPD, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, nonPublicDto)
require.NoError(t, err)
t.Run("extracts queries from provided dashboard", func(t *testing.T) {
@ -522,3 +512,21 @@ func insertTestDashboard(t *testing.T, dashboardStore *dashboardsDB.DashboardSto
dash.Data.Set("uid", dash.Uid)
return dash
}
func TestDashboardEnabledChanged(t *testing.T) {
t.Run("created isEnabled: false", func(t *testing.T) {
assert.False(t, publicDashboardIsEnabledChanged(nil, &PublicDashboard{IsEnabled: false}))
})
t.Run("created isEnabled: true", func(t *testing.T) {
assert.True(t, publicDashboardIsEnabledChanged(nil, &PublicDashboard{IsEnabled: true}))
})
t.Run("updated isEnabled same", func(t *testing.T) {
assert.False(t, publicDashboardIsEnabledChanged(&PublicDashboard{IsEnabled: true}, &PublicDashboard{IsEnabled: true}))
})
t.Run("updated isEnabled changed", func(t *testing.T) {
assert.True(t, publicDashboardIsEnabledChanged(&PublicDashboard{IsEnabled: false}, &PublicDashboard{IsEnabled: true}))
})
}

View File

@ -10,22 +10,6 @@ import (
)
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": {

View File

@ -2,22 +2,15 @@ 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
return nil
}
func hasTemplateVariables(dashboard *models.Dashboard) bool {