PublicDashboards: Audit table redesign (#68137)

This commit is contained in:
Juan Cabanas
2023-05-29 12:59:29 -03:00
committed by GitHub
parent 74e87ccbbd
commit 9890ff7c92
20 changed files with 609 additions and 356 deletions

View File

@@ -77,7 +77,7 @@ func (api *Api) RegisterAPIEndpoints() {
routing.Wrap(api.CreatePublicDashboard))
// Update Public Dashboard
api.RouteRegister.Put("/api/dashboards/uid/:dashboardUid/public-dashboards/:uid",
api.RouteRegister.Patch("/api/dashboards/uid/:dashboardUid/public-dashboards/:uid",
auth(accesscontrol.EvalPermission(dashboards.ActionDashboardsPublicWrite, uidScope)),
routing.Wrap(api.UpdatePublicDashboard))
@@ -127,22 +127,21 @@ func (api *Api) CreatePublicDashboard(c *contextmodel.ReqContext) response.Respo
return response.Err(ErrInvalidUid.Errorf("CreatePublicDashboard: invalid Uid %s", dashboardUid))
}
pd := &PublicDashboard{}
if err := web.Bind(c.Req, pd); err != nil {
pdDTO := &PublicDashboardDTO{}
if err := web.Bind(c.Req, pdDTO); err != nil {
return response.Err(ErrBadRequest.Errorf("CreatePublicDashboard: bad request data %v", err))
}
// Always set the orgID and userID from the session
pd.OrgId = c.OrgID
dto := SavePublicDashboardDTO{
pdDTO.OrgId = c.OrgID
dto := &SavePublicDashboardDTO{
UserId: c.UserID,
OrgId: c.OrgID,
DashboardUid: dashboardUid,
PublicDashboard: pd,
PublicDashboard: pdDTO,
}
//Create the public dashboard
pd, err := api.PublicDashboardService.Create(c.Req.Context(), c.SignedInUser, &dto)
pd, err := api.PublicDashboardService.Create(c.Req.Context(), c.SignedInUser, dto)
if err != nil {
return response.Err(err)
}
@@ -164,19 +163,18 @@ func (api *Api) UpdatePublicDashboard(c *contextmodel.ReqContext) response.Respo
return response.Err(ErrInvalidUid.Errorf("UpdatePublicDashboard: invalid Uid %s", uid))
}
pd := &PublicDashboard{}
if err := web.Bind(c.Req, pd); err != nil {
pdDTO := &PublicDashboardDTO{}
if err := web.Bind(c.Req, pdDTO); err != nil {
return response.Err(ErrBadRequest.Errorf("UpdatePublicDashboard: bad request data %v", err))
}
// Always set the orgID and userID from the session
pd.OrgId = c.OrgID
pd.Uid = uid
pdDTO.OrgId = c.OrgID
pdDTO.Uid = uid
dto := SavePublicDashboardDTO{
UserId: c.UserID,
OrgId: c.OrgID,
DashboardUid: dashboardUid,
PublicDashboard: pd,
PublicDashboard: pdDTO,
}
// Update the public dashboard

View File

@@ -572,7 +572,7 @@ func TestAPIUpdatePublicDashboard(t *testing.T) {
url := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards/%s", test.DashboardUid, test.PublicDashboardUid)
body := strings.NewReader(fmt.Sprintf(`{ "uid": "%s"}`, test.PublicDashboardUid))
response := callAPI(testServer, http.MethodPut, url, body, t)
response := callAPI(testServer, http.MethodPatch, url, body, t)
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
// check whether service called

View File

@@ -310,11 +310,12 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T)
require.NoError(t, err)
// Create public dashboard
isEnabled := true
savePubDashboardCmd := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
OrgId: dashboard.OrgID,
},
}

View File

@@ -42,7 +42,7 @@ func (d *PublicDashboardStoreImpl) FindAll(ctx context.Context, orgId int64) ([]
"dashboard_public.uid, dashboard_public.access_token, dashboard.uid as dashboard_uid, dashboard_public.is_enabled, dashboard.title").
Join("LEFT", "dashboard", "dashboard.uid = dashboard_public.dashboard_uid AND dashboard.org_id = dashboard_public.org_id").
Where("dashboard_public.org_id = ?", orgId).
OrderBy(" is_enabled DESC, dashboard.title IS NULL, dashboard.title ASC")
OrderBy(" dashboard.title IS NULL, dashboard.title ASC")
err := sess.Find(&resp)
return err

View File

@@ -42,14 +42,14 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
var orgId int64 = 1
aDash := insertTestDashboard(t, dashboardStore, "a", orgId, 0, true)
bDash := insertTestDashboard(t, dashboardStore, "b", orgId, 0, true)
aDash := insertTestDashboard(t, dashboardStore, "a", orgId, 0, true)
cDash := insertTestDashboard(t, dashboardStore, "c", orgId, 0, true)
// these are in order of how they should be returned from ListPUblicDashboards
a := insertPublicDashboard(t, publicdashboardStore, bDash.UID, orgId, true, PublicShareType)
b := insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
c := insertPublicDashboard(t, publicdashboardStore, aDash.UID, orgId, false, PublicShareType)
a := insertPublicDashboard(t, publicdashboardStore, aDash.UID, orgId, false, PublicShareType)
b := insertPublicDashboard(t, publicdashboardStore, bDash.UID, orgId, true, PublicShareType)
c := insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
// this is case that can happen as of now, however, postgres and mysql sort
// null in the exact opposite fashion and there is no shared syntax to sort

View File

@@ -40,20 +40,39 @@ var (
type ShareType string
type PublicDashboard struct {
Uid string `json:"uid" xorm:"pk uid"`
DashboardUid string `json:"dashboardUid" xorm:"dashboard_uid"`
OrgId int64 `json:"-" xorm:"org_id"` // Don't ever marshal orgId to Json
Uid string `json:"uid" xorm:"pk uid"`
DashboardUid string `json:"dashboardUid" xorm:"dashboard_uid"`
OrgId int64 `json:"-" xorm:"org_id"` // Don't ever marshal orgId to Json
AccessToken string `json:"accessToken" xorm:"access_token"`
CreatedBy int64 `json:"createdBy" xorm:"created_by"`
UpdatedBy int64 `json:"updatedBy" xorm:"updated_by"`
CreatedAt time.Time `json:"createdAt" xorm:"created_at"`
UpdatedAt time.Time `json:"updatedAt" xorm:"updated_at"`
//config fields
TimeSettings *TimeSettings `json:"timeSettings" xorm:"time_settings"`
IsEnabled bool `json:"isEnabled" xorm:"is_enabled"`
AccessToken string `json:"accessToken" xorm:"access_token"`
AnnotationsEnabled bool `json:"annotationsEnabled" xorm:"annotations_enabled"`
TimeSelectionEnabled bool `json:"timeSelectionEnabled" xorm:"time_selection_enabled"`
IsEnabled bool `json:"isEnabled" xorm:"is_enabled"`
AnnotationsEnabled bool `json:"annotationsEnabled" xorm:"annotations_enabled"`
Share ShareType `json:"share" xorm:"share"`
Recipients []EmailDTO `json:"recipients,omitempty" xorm:"-"`
CreatedBy int64 `json:"createdBy" xorm:"created_by"`
UpdatedBy int64 `json:"updatedBy" xorm:"updated_by"`
CreatedAt time.Time `json:"createdAt" xorm:"created_at"`
UpdatedAt time.Time `json:"updatedAt" xorm:"updated_at"`
}
type PublicDashboardDTO struct {
Uid string `json:"uid"`
DashboardUid string `json:"dashboardUid"`
OrgId int64 `json:"-"` // Don't ever marshal orgId to Json
AccessToken string `json:"accessToken"`
CreatedBy int64 `json:"createdBy"`
UpdatedBy int64 `json:"updatedBy"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
//config fields
TimeSettings *TimeSettings `json:"timeSettings"`
TimeSelectionEnabled *bool `json:"timeSelectionEnabled"`
IsEnabled *bool `json:"isEnabled"`
AnnotationsEnabled *bool `json:"annotationsEnabled"`
Share ShareType `json:"share"`
Recipients []EmailDTO `json:"recipients,omitempty"`
}
type EmailDTO struct {
@@ -130,9 +149,8 @@ func (pd PublicDashboard) BuildTimeSettings(dashboard *dashboards.Dashboard, req
// DTO for transforming user input in the api
type SavePublicDashboardDTO struct {
DashboardUid string
OrgId int64
UserId int64
PublicDashboard *PublicDashboard
PublicDashboard *PublicDashboardDTO
}
type PublicDashboardQueryDTO struct {

View File

@@ -360,13 +360,13 @@ func (_m *FakePublicDashboardService) GetOrgIdByAccessToken(ctx context.Context,
return r0, r1
}
// GetQueryDataResponse provides a mock function with given fields: ctx, skipCache, reqDTO, panelId, accessToken
func (_m *FakePublicDashboardService) GetQueryDataResponse(ctx context.Context, skipCache bool, reqDTO models.PublicDashboardQueryDTO, panelId int64, accessToken string) (*backend.QueryDataResponse, error) {
ret := _m.Called(ctx, skipCache, reqDTO, panelId, accessToken)
// GetQueryDataResponse provides a mock function with given fields: ctx, skipDSCache, reqDTO, panelId, accessToken
func (_m *FakePublicDashboardService) GetQueryDataResponse(ctx context.Context, skipDSCache bool, reqDTO models.PublicDashboardQueryDTO, panelId int64, accessToken string) (*backend.QueryDataResponse, error) {
ret := _m.Called(ctx, skipDSCache, reqDTO, panelId, accessToken)
var r0 *backend.QueryDataResponse
if rf, ok := ret.Get(0).(func(context.Context, bool, models.PublicDashboardQueryDTO, int64, string) *backend.QueryDataResponse); ok {
r0 = rf(ctx, skipCache, reqDTO, panelId, accessToken)
r0 = rf(ctx, skipDSCache, reqDTO, panelId, accessToken)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*backend.QueryDataResponse)
@@ -375,7 +375,7 @@ func (_m *FakePublicDashboardService) GetQueryDataResponse(ctx context.Context,
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, bool, models.PublicDashboardQueryDTO, int64, string) error); ok {
r1 = rf(ctx, skipCache, reqDTO, panelId, accessToken)
r1 = rf(ctx, skipDSCache, reqDTO, panelId, accessToken)
} else {
r1 = ret.Error(1)
}

View File

@@ -6,8 +6,9 @@ import (
context "context"
dashboards "github.com/grafana/grafana/pkg/services/dashboards"
models "github.com/grafana/grafana/pkg/services/publicdashboards/models"
mock "github.com/stretchr/testify/mock"
models "github.com/grafana/grafana/pkg/services/publicdashboards/models"
)
// FakePublicDashboardStore is an autogenerated mock type for the Store type

View File

@@ -688,14 +688,14 @@ func TestGetQueryDataResponse(t *testing.T) {
}}
dashboard := insertTestDashboard(t, dashboardStore, "testDashWithHiddenQuery", 1, 0, true, []map[string]interface{}{}, customPanels)
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
OrgId: dashboard.OrgID,
TimeSettings: timeSettings,
},
}
@@ -1199,11 +1199,11 @@ func TestBuildMetricRequest(t *testing.T) {
MaxDataPoints: int64(200),
}
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: publicDashboard.UID,
OrgId: publicDashboard.OrgID,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
TimeSettings: timeSettings,
@@ -1213,11 +1213,11 @@ func TestBuildMetricRequest(t *testing.T) {
publicDashboardPD, err := service.Create(context.Background(), SignedInUser, dto)
require.NoError(t, err)
isEnabled = false
nonPublicDto := &SavePublicDashboardDTO{
DashboardUid: nonPublicDashboard.UID,
OrgId: nonPublicDashboard.OrgID,
PublicDashboard: &PublicDashboard{
IsEnabled: false,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
TimeSettings: defaultPubdashTimeSettings,

View File

@@ -162,50 +162,24 @@ func (pd *PublicDashboardServiceImpl) Create(ctx context.Context, u *user.Signed
return nil, ErrDashboardIsPublic.Errorf("Create: public dashboard for dashboard %s already exists", dto.DashboardUid)
}
// set default value for time settings
if dto.PublicDashboard.TimeSettings == nil {
dto.PublicDashboard.TimeSettings = &TimeSettings{}
}
if dto.PublicDashboard.Share == "" {
dto.PublicDashboard.Share = PublicShareType
}
uid, err := pd.NewPublicDashboardUid(ctx)
if err != nil {
return nil, err
}
accessToken, err := pd.NewPublicDashboardAccessToken(ctx)
publicDashboard, err := pd.newCreatePublicDashboard(ctx, dto)
if err != nil {
return nil, err
}
cmd := SavePublicDashboardCommand{
PublicDashboard: PublicDashboard{
Uid: uid,
DashboardUid: dto.DashboardUid,
OrgId: dto.OrgId,
IsEnabled: dto.PublicDashboard.IsEnabled,
AnnotationsEnabled: dto.PublicDashboard.AnnotationsEnabled,
TimeSelectionEnabled: dto.PublicDashboard.TimeSelectionEnabled,
TimeSettings: dto.PublicDashboard.TimeSettings,
Share: dto.PublicDashboard.Share,
CreatedBy: dto.UserId,
CreatedAt: time.Now(),
AccessToken: accessToken,
},
PublicDashboard: *publicDashboard,
}
affectedRows, err := pd.store.Create(ctx, cmd)
if err != nil {
return nil, ErrInternalServerError.Errorf("Create: failed to create the public dashboard with Uid %s: %w", uid, err)
return nil, ErrInternalServerError.Errorf("Create: failed to create the public dashboard with Uid %s: %w", publicDashboard.Uid, err)
} else if affectedRows == 0 {
return nil, ErrInternalServerError.Errorf("Create: failed to create a database entry for public dashboard with Uid %s. 0 rows changed, no error reported.", uid)
return nil, ErrInternalServerError.Errorf("Create: failed to create a database entry for public dashboard with Uid %s. 0 rows changed, no error reported.", publicDashboard.Uid)
}
//Get latest public dashboard to return
newPubdash, err := pd.store.Find(ctx, uid)
newPubdash, err := pd.store.Find(ctx, publicDashboard.Uid)
if err != nil {
return nil, ErrInternalServerError.Errorf("Create: failed to find the public dashboard: %w", err)
}
@@ -241,27 +215,11 @@ func (pd *PublicDashboardServiceImpl) Update(ctx context.Context, u *user.Signed
return nil, ErrPublicDashboardNotFound.Errorf("Update: public dashboard not found by uid: %s", dto.PublicDashboard.Uid)
}
// set default value for time settings
if dto.PublicDashboard.TimeSettings == nil {
dto.PublicDashboard.TimeSettings = &TimeSettings{}
}
if dto.PublicDashboard.Share == "" {
dto.PublicDashboard.Share = existingPubdash.Share
}
publicDashboard := newUpdatePublicDashboard(dto, existingPubdash)
// set values to update
cmd := SavePublicDashboardCommand{
PublicDashboard: PublicDashboard{
Uid: existingPubdash.Uid,
IsEnabled: dto.PublicDashboard.IsEnabled,
AnnotationsEnabled: dto.PublicDashboard.AnnotationsEnabled,
TimeSelectionEnabled: dto.PublicDashboard.TimeSelectionEnabled,
TimeSettings: dto.PublicDashboard.TimeSettings,
Share: dto.PublicDashboard.Share,
UpdatedBy: dto.UserId,
UpdatedAt: time.Now(),
},
PublicDashboard: *publicDashboard,
}
// persist
@@ -449,3 +407,83 @@ func GenerateAccessToken() (string, error) {
}
return fmt.Sprintf("%x", token[:]), nil
}
func (pd *PublicDashboardServiceImpl) newCreatePublicDashboard(ctx context.Context, dto *SavePublicDashboardDTO) (*PublicDashboard, error) {
uid, err := pd.NewPublicDashboardUid(ctx)
if err != nil {
return nil, err
}
accessToken, err := pd.NewPublicDashboardAccessToken(ctx)
if err != nil {
return nil, err
}
isEnabled := returnValueOrDefault(dto.PublicDashboard.IsEnabled, false)
annotationsEnabled := returnValueOrDefault(dto.PublicDashboard.AnnotationsEnabled, false)
timeSelectionEnabled := returnValueOrDefault(dto.PublicDashboard.TimeSelectionEnabled, false)
timeSettings := dto.PublicDashboard.TimeSettings
if dto.PublicDashboard.TimeSettings == nil {
timeSettings = &TimeSettings{}
}
share := dto.PublicDashboard.Share
if dto.PublicDashboard.Share == "" {
share = PublicShareType
}
return &PublicDashboard{
Uid: uid,
DashboardUid: dto.DashboardUid,
OrgId: dto.PublicDashboard.OrgId,
IsEnabled: isEnabled,
AnnotationsEnabled: annotationsEnabled,
TimeSelectionEnabled: timeSelectionEnabled,
TimeSettings: timeSettings,
Share: share,
CreatedBy: dto.UserId,
CreatedAt: time.Now(),
AccessToken: accessToken,
}, nil
}
func newUpdatePublicDashboard(dto *SavePublicDashboardDTO, pd *PublicDashboard) *PublicDashboard {
pubdashDTO := dto.PublicDashboard
timeSelectionEnabled := returnValueOrDefault(pubdashDTO.TimeSelectionEnabled, pd.TimeSelectionEnabled)
isEnabled := returnValueOrDefault(pubdashDTO.IsEnabled, pd.IsEnabled)
annotationsEnabled := returnValueOrDefault(pubdashDTO.AnnotationsEnabled, pd.AnnotationsEnabled)
timeSettings := pubdashDTO.TimeSettings
if pubdashDTO.TimeSettings == nil {
if pd.TimeSettings == nil {
timeSettings = &TimeSettings{}
} else {
timeSettings = pd.TimeSettings
}
}
share := pubdashDTO.Share
if pubdashDTO.Share == "" {
share = pd.Share
}
return &PublicDashboard{
Uid: pd.Uid,
IsEnabled: isEnabled,
AnnotationsEnabled: annotationsEnabled,
TimeSelectionEnabled: timeSelectionEnabled,
TimeSettings: timeSettings,
Share: share,
UpdatedBy: dto.UserId,
UpdatedAt: time.Now(),
}
}
func returnValueOrDefault(value *bool, defaultValue bool) bool {
if value != nil {
return *value
}
return defaultValue
}

View File

@@ -205,17 +205,18 @@ func TestCreatePublicDashboard(t *testing.T) {
serviceWrapper: serviceWrapper,
}
isEnabled, annotationsEnabled, timeSelectionEnabled := true, false, true
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
AnnotationsEnabled: false,
TimeSelectionEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
AnnotationsEnabled: &annotationsEnabled,
TimeSelectionEnabled: &timeSelectionEnabled,
Share: EmailShareType,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
OrgId: dashboard.OrgID,
TimeSettings: timeSettings,
},
}
@@ -230,10 +231,10 @@ func TestCreatePublicDashboard(t *testing.T) {
assert.Equal(t, dashboard.UID, pubdash.DashboardUid)
assert.Equal(t, dashboard.OrgID, pubdash.OrgId)
assert.Equal(t, dto.UserId, pubdash.CreatedBy)
assert.Equal(t, dto.PublicDashboard.AnnotationsEnabled, pubdash.AnnotationsEnabled)
assert.Equal(t, dto.PublicDashboard.TimeSelectionEnabled, pubdash.TimeSelectionEnabled)
assert.Equal(t, *dto.PublicDashboard.AnnotationsEnabled, pubdash.AnnotationsEnabled)
assert.Equal(t, *dto.PublicDashboard.TimeSelectionEnabled, pubdash.TimeSelectionEnabled)
// ExistsEnabledByDashboardUid set by parameters
assert.Equal(t, dto.PublicDashboard.IsEnabled, pubdash.IsEnabled)
assert.Equal(t, *dto.PublicDashboard.IsEnabled, pubdash.IsEnabled)
// CreatedAt set to non-zero time
assert.NotEqual(t, &time.Time{}, pubdash.CreatedAt)
// Time settings set by db
@@ -244,6 +245,81 @@ func TestCreatePublicDashboard(t *testing.T) {
require.NoError(t, err, "expected a valid UUID, got %s", pubdash.AccessToken)
})
trueBooleanField := true
testCases := []struct {
Name string
IsEnabled *bool
TimeSelectionEnabled *bool
AnnotationsEnabled *bool
}{
{
Name: "isEnabled",
IsEnabled: nil,
TimeSelectionEnabled: &trueBooleanField,
AnnotationsEnabled: &trueBooleanField,
},
{
Name: "timeSelectionEnabled",
IsEnabled: &trueBooleanField,
TimeSelectionEnabled: nil,
AnnotationsEnabled: &trueBooleanField,
},
{
Name: "annotationsEnabled",
IsEnabled: &trueBooleanField,
TimeSelectionEnabled: &trueBooleanField,
AnnotationsEnabled: nil,
},
{
Name: "isEnabled, timeSelectionEnabled and annotationsEnabled",
IsEnabled: nil,
TimeSelectionEnabled: nil,
AnnotationsEnabled: nil,
},
}
for _, tt := range testCases {
t.Run(fmt.Sprintf("Create public dashboard with %s null boolean fields stores them as false", tt.Name), func(t *testing.T) {
sqlStore := db.InitTestDB(t)
quotaService := quotatest.New(false, nil)
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
require.NoError(t, err)
publicdashboardStore := database.ProvideStore(sqlStore)
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
service := &PublicDashboardServiceImpl{
log: log.New("test.logger"),
store: publicdashboardStore,
serviceWrapper: serviceWrapper,
}
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
UserId: 7,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: tt.IsEnabled,
TimeSelectionEnabled: tt.TimeSelectionEnabled,
AnnotationsEnabled: tt.AnnotationsEnabled,
Share: PublicShareType,
DashboardUid: "NOTTHESAME",
OrgId: dashboard.OrgID,
TimeSettings: timeSettings,
},
}
_, err = service.Create(context.Background(), SignedInUser, dto)
require.NoError(t, err)
pubdash, err := service.FindByDashboardUid(context.Background(), dashboard.OrgID, dashboard.UID)
require.NoError(t, err)
assertFalseIfNull(t, pubdash.IsEnabled, dto.PublicDashboard.IsEnabled)
assertFalseIfNull(t, pubdash.TimeSelectionEnabled, dto.PublicDashboard.TimeSelectionEnabled)
assertFalseIfNull(t, pubdash.AnnotationsEnabled, dto.PublicDashboard.AnnotationsEnabled)
})
}
t.Run("Validate pubdash has default time setting value", func(t *testing.T) {
sqlStore := db.InitTestDB(t)
quotaService := quotatest.New(false, nil)
@@ -259,14 +335,14 @@ func TestCreatePublicDashboard(t *testing.T) {
serviceWrapper: serviceWrapper,
}
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
OrgId: dashboard.OrgID,
},
}
@@ -294,14 +370,14 @@ func TestCreatePublicDashboard(t *testing.T) {
serviceWrapper: serviceWrapper,
}
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
OrgId: dashboard.OrgID,
},
}
@@ -321,7 +397,7 @@ func TestCreatePublicDashboard(t *testing.T) {
IsEnabled: true,
AnnotationsEnabled: false,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
OrgId: dashboard.OrgID,
TimeSettings: timeSettings,
}
@@ -339,14 +415,14 @@ func TestCreatePublicDashboard(t *testing.T) {
serviceWrapper: serviceWrapper,
}
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: "an-id",
OrgId: 8,
UserId: 7,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
OrgId: dashboard.OrgID,
},
}
@@ -376,13 +452,13 @@ func TestCreatePublicDashboard(t *testing.T) {
serviceWrapper: serviceWrapper,
}
isEnabled, annotationsEnabled := true, false
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboard{
AnnotationsEnabled: false,
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
AnnotationsEnabled: &annotationsEnabled,
IsEnabled: &isEnabled,
TimeSettings: timeSettings,
},
}
@@ -408,14 +484,14 @@ func TestCreatePublicDashboard(t *testing.T) {
serviceWrapper: serviceWrapper,
}
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
OrgId: dashboard.OrgID,
},
}
@@ -429,6 +505,14 @@ func TestCreatePublicDashboard(t *testing.T) {
})
}
func assertFalseIfNull(t *testing.T, expectedValue bool, nullableValue *bool) {
if nullableValue == nil {
assert.Equal(t, expectedValue, false)
} else {
assert.Equal(t, expectedValue, *nullableValue)
}
}
func TestUpdatePublicDashboard(t *testing.T) {
t.Run("Updating public dashboard", func(t *testing.T) {
sqlStore := db.InitTestDB(t)
@@ -445,14 +529,14 @@ func TestUpdatePublicDashboard(t *testing.T) {
serviceWrapper: serviceWrapper,
}
isEnabled, annotationsEnabled, timeSelectionEnabled := true, false, false
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboard{
AnnotationsEnabled: false,
IsEnabled: true,
TimeSelectionEnabled: false,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
AnnotationsEnabled: &annotationsEnabled,
TimeSelectionEnabled: &timeSelectionEnabled,
TimeSettings: timeSettings,
},
}
@@ -461,21 +545,21 @@ func TestUpdatePublicDashboard(t *testing.T) {
savedPubdash, err := service.Create(context.Background(), SignedInUser, dto)
require.NoError(t, err)
isEnabled, annotationsEnabled, timeSelectionEnabled = true, true, true
// attempt to overwrite settings
dto = &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 8,
PublicDashboard: &PublicDashboard{
PublicDashboard: &PublicDashboardDTO{
Uid: savedPubdash.Uid,
OrgId: 9,
DashboardUid: "abc1234",
CreatedBy: 9,
CreatedAt: time.Time{},
IsEnabled: true,
AnnotationsEnabled: true,
TimeSelectionEnabled: true,
IsEnabled: &isEnabled,
AnnotationsEnabled: &annotationsEnabled,
TimeSelectionEnabled: &timeSelectionEnabled,
TimeSettings: timeSettings,
AccessToken: "NOTAREALUUID",
},
@@ -491,9 +575,9 @@ func TestUpdatePublicDashboard(t *testing.T) {
assert.Equal(t, savedPubdash.AccessToken, updatedPubdash.AccessToken)
// gets updated
assert.Equal(t, dto.PublicDashboard.IsEnabled, updatedPubdash.IsEnabled)
assert.Equal(t, dto.PublicDashboard.AnnotationsEnabled, updatedPubdash.AnnotationsEnabled)
assert.Equal(t, dto.PublicDashboard.TimeSelectionEnabled, updatedPubdash.TimeSelectionEnabled)
assert.Equal(t, *dto.PublicDashboard.IsEnabled, updatedPubdash.IsEnabled)
assert.Equal(t, *dto.PublicDashboard.AnnotationsEnabled, updatedPubdash.AnnotationsEnabled)
assert.Equal(t, *dto.PublicDashboard.TimeSelectionEnabled, updatedPubdash.TimeSelectionEnabled)
assert.Equal(t, dto.PublicDashboard.TimeSettings, updatedPubdash.TimeSettings)
assert.Equal(t, dto.UserId, updatedPubdash.UpdatedBy)
assert.NotEqual(t, &time.Time{}, updatedPubdash.UpdatedAt)
@@ -515,12 +599,12 @@ func TestUpdatePublicDashboard(t *testing.T) {
serviceWrapper: serviceWrapper,
}
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboard{
IsEnabled: true,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
TimeSettings: timeSettings,
},
}
@@ -531,17 +615,16 @@ func TestUpdatePublicDashboard(t *testing.T) {
// attempt to overwrite settings
dto = &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
OrgId: dashboard.OrgID,
UserId: 8,
PublicDashboard: &PublicDashboard{
PublicDashboard: &PublicDashboardDTO{
Uid: savedPubdash.Uid,
OrgId: 9,
DashboardUid: "abc1234",
CreatedBy: 9,
CreatedAt: time.Time{},
IsEnabled: true,
AccessToken: "NOTAREALUUID",
IsEnabled: &isEnabled,
TimeSettings: &TimeSettings{},
AccessToken: "NOTAREALUUID",
},
}
@@ -550,6 +633,132 @@ func TestUpdatePublicDashboard(t *testing.T) {
assert.Equal(t, &TimeSettings{}, updatedPubdash.TimeSettings)
})
trueBooleanField := true
timeSettings := &TimeSettings{From: "now-8", To: "now"}
shareType := EmailShareType
testCases := []struct {
Name string
IsEnabled *bool
TimeSelectionEnabled *bool
AnnotationsEnabled *bool
TimeSettings *TimeSettings
ShareType ShareType
}{
{
Name: "isEnabled",
IsEnabled: nil,
TimeSelectionEnabled: &trueBooleanField,
AnnotationsEnabled: &trueBooleanField,
TimeSettings: timeSettings,
ShareType: shareType,
},
{
Name: "timeSelectionEnabled",
IsEnabled: &trueBooleanField,
TimeSelectionEnabled: nil,
AnnotationsEnabled: &trueBooleanField,
TimeSettings: timeSettings,
ShareType: shareType,
},
{
Name: "annotationsEnabled",
IsEnabled: &trueBooleanField,
TimeSelectionEnabled: &trueBooleanField,
AnnotationsEnabled: nil,
TimeSettings: timeSettings,
ShareType: shareType,
},
{
Name: "isEnabled, timeSelectionEnabled and annotationsEnabled",
IsEnabled: nil,
TimeSelectionEnabled: nil,
AnnotationsEnabled: nil,
TimeSettings: nil,
ShareType: "",
},
}
for _, tt := range testCases {
t.Run(fmt.Sprintf("Update public dashboard with %s null boolean fields let those fields with old persisted value", tt.Name), func(t *testing.T) {
sqlStore := db.InitTestDB(t)
quotaService := quotatest.New(false, nil)
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
require.NoError(t, err)
publicdashboardStore := database.ProvideStore(sqlStore)
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
service := &PublicDashboardServiceImpl{
log: log.New("test.logger"),
store: publicdashboardStore,
serviceWrapper: serviceWrapper,
}
isEnabled, annotationsEnabled, timeSelectionEnabled := true, true, false
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
UserId: 7,
PublicDashboard: &PublicDashboardDTO{
IsEnabled: &isEnabled,
AnnotationsEnabled: &annotationsEnabled,
TimeSelectionEnabled: &timeSelectionEnabled,
TimeSettings: timeSettings,
Share: PublicShareType,
},
}
// insert initial pubdash
savedPubdash, err := service.Create(context.Background(), SignedInUser, dto)
require.NoError(t, err)
// attempt to overwrite settings
dto = &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
UserId: 8,
PublicDashboard: &PublicDashboardDTO{
Uid: savedPubdash.Uid,
OrgId: 9,
DashboardUid: "abc1234",
CreatedBy: 9,
CreatedAt: time.Time{},
IsEnabled: tt.IsEnabled,
AnnotationsEnabled: tt.AnnotationsEnabled,
TimeSelectionEnabled: tt.TimeSelectionEnabled,
TimeSettings: tt.TimeSettings,
Share: tt.ShareType,
AccessToken: "NOTAREALUUID",
},
}
updatedPubdash, err := service.Update(context.Background(), SignedInUser, dto)
require.NoError(t, err)
assertOldValueIfNull(t, updatedPubdash.IsEnabled, savedPubdash.IsEnabled, dto.PublicDashboard.IsEnabled)
assertOldValueIfNull(t, updatedPubdash.AnnotationsEnabled, savedPubdash.AnnotationsEnabled, dto.PublicDashboard.AnnotationsEnabled)
assertOldValueIfNull(t, updatedPubdash.TimeSelectionEnabled, savedPubdash.TimeSelectionEnabled, dto.PublicDashboard.TimeSelectionEnabled)
if dto.PublicDashboard.TimeSettings == nil {
assert.Equal(t, updatedPubdash.TimeSettings, savedPubdash.TimeSettings)
} else {
assert.Equal(t, updatedPubdash.TimeSettings, dto.PublicDashboard.TimeSettings)
}
if dto.PublicDashboard.Share == "" {
assert.Equal(t, updatedPubdash.Share, savedPubdash.Share)
} else {
assert.Equal(t, updatedPubdash.Share, dto.PublicDashboard.Share)
}
})
}
}
func assertOldValueIfNull(t *testing.T, expectedValue bool, oldValue bool, nullableValue *bool) {
if nullableValue == nil {
assert.Equal(t, expectedValue, oldValue)
} else {
assert.Equal(t, expectedValue, *nullableValue)
}
}
func TestDeletePublicDashboard(t *testing.T) {

View File

@@ -10,14 +10,14 @@ import (
func TestValidatePublicDashboard(t *testing.T) {
t.Run("Returns no error when valid shareType value is received", func(t *testing.T) {
dto := &SavePublicDashboardDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: &PublicDashboard{Share: EmailShareType}}
dto := &SavePublicDashboardDTO{DashboardUid: "abc123", UserId: 1, PublicDashboard: &PublicDashboardDTO{Share: EmailShareType}}
err := ValidatePublicDashboard(dto)
require.NoError(t, err)
})
t.Run("Returns error when invalid shareType value", func(t *testing.T) {
dto := &SavePublicDashboardDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: &PublicDashboard{Share: "invalid"}}
dto := &SavePublicDashboardDTO{DashboardUid: "abc123", UserId: 1, PublicDashboard: &PublicDashboardDTO{Share: "invalid"}}
err := ValidatePublicDashboard(dto)
require.Error(t, err)