mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Public Dashboards: Remove join from dashboards table (#98471)
This commit is contained in:
parent
aac8626326
commit
88f8f2203b
@ -7,13 +7,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@ -43,7 +40,7 @@ func ProvideStore(sqlStore db.DB, cfg *setting.Cfg, features featuremgmt.Feature
|
||||
}
|
||||
|
||||
// FindAllWithPagination Returns a list of public dashboards by orgId, based on permissions and with pagination
|
||||
func (d *PublicDashboardStoreImpl) FindAllWithPagination(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error) {
|
||||
func (d *PublicDashboardStoreImpl) FindAll(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error) {
|
||||
resp := &PublicDashboardListResponseWithPagination{
|
||||
PublicDashboards: make([]*PublicDashboardListResponse, 0),
|
||||
TotalCount: 0,
|
||||
@ -55,24 +52,14 @@ func (d *PublicDashboardStoreImpl) FindAllWithPagination(ctx context.Context, qu
|
||||
}
|
||||
|
||||
pubdashBuilder := db.NewSqlBuilder(d.cfg, d.features, d.sqlStore.GetDialect(), recursiveQueriesAreSupported)
|
||||
pubdashBuilder.Write("SELECT dashboard_public.uid, dashboard_public.access_token, dashboard.uid as dashboard_uid, dashboard_public.is_enabled, dashboard.title, dashboard.slug")
|
||||
pubdashBuilder.Write("SELECT uid, access_token, dashboard_uid, is_enabled")
|
||||
pubdashBuilder.Write(" FROM dashboard_public")
|
||||
pubdashBuilder.Write(" JOIN dashboard ON dashboard.uid = dashboard_public.dashboard_uid AND dashboard.org_id = dashboard_public.org_id")
|
||||
pubdashBuilder.Write(` WHERE dashboard_public.org_id = ?`, query.OrgID)
|
||||
if query.User.OrgRole != org.RoleAdmin {
|
||||
pubdashBuilder.WriteDashboardPermissionFilter(query.User, dashboardaccess.PERMISSION_VIEW, searchstore.TypeDashboard)
|
||||
}
|
||||
pubdashBuilder.Write(" ORDER BY dashboard.title")
|
||||
pubdashBuilder.Write(d.sqlStore.GetDialect().LimitOffset(int64(query.Limit), int64(query.Offset)))
|
||||
pubdashBuilder.Write(` WHERE org_id = ?`, query.OrgID)
|
||||
|
||||
counterBuilder := db.NewSqlBuilder(d.cfg, d.features, d.sqlStore.GetDialect(), recursiveQueriesAreSupported)
|
||||
counterBuilder.Write("SELECT COUNT(*)")
|
||||
counterBuilder.Write(" FROM dashboard_public")
|
||||
counterBuilder.Write(" JOIN dashboard ON dashboard.uid = dashboard_public.dashboard_uid AND dashboard.org_id = dashboard_public.org_id")
|
||||
counterBuilder.Write(` WHERE dashboard_public.org_id = ?`, query.OrgID)
|
||||
if query.User.OrgRole != org.RoleAdmin {
|
||||
counterBuilder.WriteDashboardPermissionFilter(query.User, dashboardaccess.PERMISSION_VIEW, searchstore.TypeDashboard)
|
||||
}
|
||||
counterBuilder.Write(` WHERE org_id = ?`, query.OrgID)
|
||||
|
||||
err = d.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
err := sess.SQL(pubdashBuilder.GetSQLString(), pubdashBuilder.GetParams()...).Find(&resp.PublicDashboards)
|
||||
|
@ -79,7 +79,7 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
|
||||
cPublicDash = insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
|
||||
}
|
||||
|
||||
t.Run("FindAllWithPagination will return dashboard list based on orgId with pagination", func(t *testing.T) {
|
||||
t.Run("FindAll will return dashboard list based on orgId with pagination", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
// should not be included in response
|
||||
@ -102,69 +102,19 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
|
||||
Limit: 50,
|
||||
Offset: 0,
|
||||
}
|
||||
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
|
||||
resp, err := publicdashboardStore.FindAll(context.Background(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, resp.PublicDashboards, 3)
|
||||
assert.Equal(t, resp.PublicDashboards[0].Uid, aPublicDash.Uid)
|
||||
assert.Equal(t, resp.PublicDashboards[1].Uid, bPublicDash.Uid)
|
||||
assert.Equal(t, resp.PublicDashboards[2].Uid, cPublicDash.Uid)
|
||||
uids := make([]string, len(resp.PublicDashboards))
|
||||
for i, pubdash := range resp.PublicDashboards {
|
||||
uids[i] = pubdash.Uid
|
||||
}
|
||||
assert.Contains(t, uids, aPublicDash.Uid)
|
||||
assert.Contains(t, uids, bPublicDash.Uid)
|
||||
assert.Contains(t, uids, cPublicDash.Uid)
|
||||
assert.Equal(t, resp.TotalCount, int64(3))
|
||||
})
|
||||
|
||||
t.Run("FindAllWithPagination will return dashboard list based on read permissions with pagination", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
permissions := []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", aDash.UID)},
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", cDash.UID)},
|
||||
}
|
||||
|
||||
usr := &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
|
||||
actest.AddUserPermissionToDB(t, sqlStore, usr)
|
||||
|
||||
query := &PublicDashboardListQuery{
|
||||
User: usr,
|
||||
OrgID: orgId,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
Offset: 0,
|
||||
}
|
||||
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, resp.PublicDashboards, 2)
|
||||
assert.Equal(t, resp.PublicDashboards[0].Uid, aPublicDash.Uid)
|
||||
assert.Equal(t, resp.PublicDashboards[1].Uid, cPublicDash.Uid)
|
||||
assert.Equal(t, resp.TotalCount, int64(2))
|
||||
})
|
||||
|
||||
t.Run("FindAllWithPagination will return empty dashboard list based on read permissions with pagination", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
permissions := []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:another-dashboard-uid"},
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:another-dashboard-2-uid"},
|
||||
}
|
||||
|
||||
usr := &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
|
||||
actest.AddUserPermissionToDB(t, sqlStore, usr)
|
||||
|
||||
query := &PublicDashboardListQuery{
|
||||
User: usr,
|
||||
OrgID: orgId,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
Offset: 0,
|
||||
}
|
||||
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, resp.PublicDashboards, 0)
|
||||
assert.Equal(t, resp.TotalCount, int64(0))
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntegrationExistsEnabledByAccessToken(t *testing.T) {
|
||||
|
@ -136,8 +136,8 @@ func (_m *FakePublicDashboardStore) Find(ctx context.Context, uid string) (*mode
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FindAllWithPagination provides a mock function with given fields: ctx, query
|
||||
func (_m *FakePublicDashboardStore) FindAllWithPagination(ctx context.Context, query *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error) {
|
||||
// FindAll provides a mock function with given fields: ctx, query
|
||||
func (_m *FakePublicDashboardStore) FindAll(ctx context.Context, query *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
var r0 *models.PublicDashboardListResponseWithPagination
|
||||
|
@ -53,7 +53,7 @@ type Store interface {
|
||||
Find(ctx context.Context, uid string) (*PublicDashboard, error)
|
||||
FindByAccessToken(ctx context.Context, accessToken string) (*PublicDashboard, error)
|
||||
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||
FindAllWithPagination(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error)
|
||||
FindAll(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error)
|
||||
Create(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
|
||||
Update(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
|
||||
Delete(ctx context.Context, uid string) (int64, error)
|
||||
|
@ -15,26 +15,31 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/service/intervalv2"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func newPublicDashboardServiceImpl(
|
||||
t *testing.T,
|
||||
store *sqlstore.SQLStore,
|
||||
cfg *setting.Cfg,
|
||||
publicDashboardStore publicdashboards.Store,
|
||||
dashboardService dashboards.DashboardService,
|
||||
annotationsRepo annotations.Repository,
|
||||
) (*PublicDashboardServiceImpl, db.DB, *setting.Cfg) {
|
||||
t.Helper()
|
||||
|
||||
db, cfg := db.InitTestDBWithCfg(t)
|
||||
tagService := tagimpl.ProvideService(db)
|
||||
if store == nil {
|
||||
store, cfg = db.InitTestDBWithCfg(t)
|
||||
}
|
||||
tagService := tagimpl.ProvideService(store)
|
||||
if annotationsRepo == nil {
|
||||
annotationsRepo = annotationsimpl.ProvideService(db, cfg, featuremgmt.WithFeatures(), tagService, tracing.InitializeTracerForTest(), nil)
|
||||
annotationsRepo = annotationsimpl.ProvideService(store, cfg, featuremgmt.WithFeatures(), tagService, tracing.InitializeTracerForTest(), nil)
|
||||
}
|
||||
|
||||
if publicDashboardStore == nil {
|
||||
publicDashboardStore = database.ProvideStore(db, cfg, featuremgmt.WithFeatures())
|
||||
publicDashboardStore = database.ProvideStore(store, cfg, featuremgmt.WithFeatures())
|
||||
}
|
||||
serviceWrapper := ProvideServiceWrapper(publicDashboardStore)
|
||||
|
||||
@ -50,5 +55,5 @@ func newPublicDashboardServiceImpl(
|
||||
serviceWrapper: serviceWrapper,
|
||||
license: license,
|
||||
features: featuremgmt.WithFeatures(),
|
||||
}, db, cfg
|
||||
}, store, cfg
|
||||
}
|
||||
|
@ -677,7 +677,7 @@ const (
|
||||
|
||||
func TestGetQueryDataResponse(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, _ := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, _ := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
fakeQueryService := &query.FakeQueryService{}
|
||||
fakeQueryService.On("QueryData", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&backend.QueryDataResponse{}, nil)
|
||||
service.QueryDataService = fakeQueryService
|
||||
@ -739,7 +739,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
Return(&PublicDashboard{Uid: "uid1", IsEnabled: true}, nil)
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboards.NewDashboard("dash1"), nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, nil)
|
||||
|
||||
reqDTO := AnnotationsQueryDTO{
|
||||
From: 1,
|
||||
@ -792,7 +792,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
|
||||
annotationsRepo.On("Find", mock.Anything, mock.Anything).Return([]*annotations.ItemDTO{
|
||||
{
|
||||
@ -849,7 +849,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
|
||||
annotationsRepo.On("Find", mock.Anything, mock.Anything).Return([]*annotations.ItemDTO{
|
||||
{
|
||||
@ -918,7 +918,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
|
||||
annotationsRepo.On("Find", mock.Anything, mock.Anything).Return([]*annotations.ItemDTO{
|
||||
{
|
||||
@ -958,7 +958,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
fakeStore.On("FindByAccessToken", mock.Anything, mock.AnythingOfType("string")).Return(pubdash, nil)
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, nil)
|
||||
|
||||
items, err := service.FindAnnotations(context.Background(), AnnotationsQueryDTO{}, "abc123")
|
||||
|
||||
@ -988,7 +988,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
fakeStore.On("FindByAccessToken", mock.Anything, mock.AnythingOfType("string")).Return(pubdash, nil)
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, nil)
|
||||
|
||||
items, err := service.FindAnnotations(context.Background(), AnnotationsQueryDTO{}, "abc123")
|
||||
|
||||
@ -1020,7 +1020,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dash, nil)
|
||||
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
|
||||
items, err := service.FindAnnotations(context.Background(), AnnotationsQueryDTO{}, "abc123")
|
||||
|
||||
@ -1061,7 +1061,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
},
|
||||
}, nil).Maybe()
|
||||
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, annotationsRepo)
|
||||
|
||||
items, err := service.FindAnnotations(context.Background(), AnnotationsQueryDTO{}, "abc123")
|
||||
|
||||
@ -1084,7 +1084,7 @@ func TestFindAnnotations(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetMetricRequest(t *testing.T) {
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, nil, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, "", true, []map[string]interface{}{}, nil)
|
||||
@ -1165,7 +1165,7 @@ func TestGetUniqueDashboardDatasourceUids(t *testing.T) {
|
||||
|
||||
func TestBuildMetricRequest(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@ -363,11 +364,58 @@ func (pd *PublicDashboardServiceImpl) FindAllWithPagination(ctx context.Context,
|
||||
ctx, span := tracer.Start(ctx, "publicdashboards.FindAllWithPagination")
|
||||
defer span.End()
|
||||
query.Offset = query.Limit * (query.Page - 1)
|
||||
resp, err := pd.store.FindAllWithPagination(ctx, query)
|
||||
resp, err := pd.store.FindAll(ctx, query)
|
||||
if err != nil {
|
||||
return nil, ErrInternalServerError.Errorf("FindAllWithPagination: %w", err)
|
||||
return nil, ErrInternalServerError.Errorf("FindAllWithPagination: GetPublicDashboards: %w", err)
|
||||
}
|
||||
|
||||
// join in the dashboard data
|
||||
dashUIDs := make([]string, len(resp.PublicDashboards))
|
||||
for i, pubdash := range resp.PublicDashboards {
|
||||
dashUIDs[i] = pubdash.DashboardUid
|
||||
}
|
||||
|
||||
dashboardsFound, err := pd.dashboardService.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{OrgId: query.OrgID, DashboardUIDs: dashUIDs, SignedInUser: query.User})
|
||||
if err != nil {
|
||||
return nil, ErrInternalServerError.Errorf("FindAllWithPagination: GetDashboards: %w", err)
|
||||
}
|
||||
|
||||
dashMap := make(map[string]dashboards.DashboardSearchProjection)
|
||||
for _, dash := range dashboardsFound {
|
||||
dashMap[dash.UID] = dash
|
||||
}
|
||||
|
||||
// add dashboard title & slug to response, and
|
||||
// remove any public dashboards that don't have a corresponding active dashboard that the user has access to
|
||||
idx := 0
|
||||
for _, pubdash := range resp.PublicDashboards {
|
||||
if dash, exists := dashMap[pubdash.DashboardUid]; exists {
|
||||
pubdash.Title = dash.Title
|
||||
pubdash.Slug = dash.Slug
|
||||
resp.PublicDashboards[idx] = pubdash
|
||||
idx++
|
||||
} else {
|
||||
resp.TotalCount--
|
||||
}
|
||||
}
|
||||
resp.PublicDashboards = resp.PublicDashboards[:idx]
|
||||
|
||||
// sort by title
|
||||
sort.Slice(resp.PublicDashboards, func(i, j int) bool {
|
||||
return resp.PublicDashboards[i].Title < resp.PublicDashboards[j].Title
|
||||
})
|
||||
|
||||
// and now paginate
|
||||
start := query.Offset
|
||||
end := start + query.Limit
|
||||
if start > len(resp.PublicDashboards) {
|
||||
start = len(resp.PublicDashboards)
|
||||
}
|
||||
if end > len(resp.PublicDashboards) {
|
||||
end = len(resp.PublicDashboards)
|
||||
}
|
||||
resp.PublicDashboards = resp.PublicDashboards[start:end]
|
||||
|
||||
resp.Page = query.Page
|
||||
resp.PerPage = query.Limit
|
||||
|
||||
|
@ -16,17 +16,27 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
dashsvc "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/service/intervalv2"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
|
||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
@ -387,7 +397,7 @@ func TestGetPublicDashboardForView(t *testing.T) {
|
||||
fakeStore.On("FindByAccessToken", mock.Anything, mock.Anything).Return(test.StoreResp.pd, test.StoreResp.err)
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(test.StoreResp.d, test.StoreResp.err)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, nil)
|
||||
|
||||
dashboardFullWithMeta, err := service.GetPublicDashboardForView(context.Background(), test.AccessToken)
|
||||
if test.ErrResp != nil {
|
||||
@ -496,7 +506,7 @@ func TestGetPublicDashboard(t *testing.T) {
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(test.StoreResp.d, test.StoreResp.err)
|
||||
fakeStore := &FakePublicDashboardStore{}
|
||||
fakeStore.On("FindByAccessToken", mock.Anything, mock.Anything).Return(test.StoreResp.pd, test.StoreResp.err)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, nil)
|
||||
|
||||
pdc, dash, err := service.FindPublicDashboardAndDashboardByAccessToken(context.Background(), test.AccessToken)
|
||||
if test.ErrResp != nil {
|
||||
@ -559,7 +569,7 @@ func TestGetEnabledPublicDashboard(t *testing.T) {
|
||||
fakeStore.On("FindByAccessToken", mock.Anything, mock.Anything).Return(test.StoreResp.pd, test.StoreResp.err)
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(test.StoreResp.d, test.StoreResp.err)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, fakeStore, fakeDashboardService, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, fakeStore, fakeDashboardService, nil)
|
||||
|
||||
pdc, dash, err := service.FindEnabledPublicDashboardAndDashboardByAccessToken(context.Background(), test.AccessToken)
|
||||
if test.ErrResp != nil {
|
||||
@ -583,7 +593,7 @@ func TestGetEnabledPublicDashboard(t *testing.T) {
|
||||
func TestCreatePublicDashboard(t *testing.T) {
|
||||
t.Run("Create public dashboard", func(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
@ -664,7 +674,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
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) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
require.NoError(t, err)
|
||||
@ -696,7 +706,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
|
||||
t.Run("Validate pubdash has default time setting value", func(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
require.NoError(t, err)
|
||||
@ -723,7 +733,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
|
||||
t.Run("Creates pubdash whose dashboard has template variables successfully", func(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
require.NoError(t, err)
|
||||
@ -769,7 +779,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, publicDashboardStore, fakeDashboardService, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, publicDashboardStore, fakeDashboardService, nil)
|
||||
|
||||
isEnabled := true
|
||||
dto := &SavePublicDashboardDTO{
|
||||
@ -789,7 +799,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
|
||||
t.Run("Create public dashboard with given pubdash uid", func(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
require.NoError(t, err)
|
||||
@ -835,7 +845,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
publicDashboardStore.On("FindByDashboardUid", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrPublicDashboardNotFound.Errorf(""))
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
fakeDashboardService.On("GetDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, publicDashboardStore, fakeDashboardService, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, publicDashboardStore, fakeDashboardService, nil)
|
||||
|
||||
isEnabled := true
|
||||
dto := &SavePublicDashboardDTO{
|
||||
@ -855,7 +865,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
|
||||
t.Run("Create public dashboard with given pubdash access token", func(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
require.NoError(t, err)
|
||||
@ -895,7 +905,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
|
||||
publicDashboardStore := &FakePublicDashboardStore{}
|
||||
publicDashboardStore.On("FindByAccessToken", mock.Anything, mock.Anything).Return(pubdash, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, publicDashboardStore, nil, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, publicDashboardStore, nil, nil)
|
||||
|
||||
_, err := service.NewPublicDashboardAccessToken(context.Background())
|
||||
require.Error(t, err)
|
||||
@ -907,7 +917,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
publicdashboardStore.On("FindByDashboardUid", mock.Anything, mock.Anything, mock.Anything).Return(&PublicDashboard{Uid: "newPubdashUid"}, nil)
|
||||
publicdashboardStore.On("Find", mock.Anything, mock.Anything).Return(nil, nil)
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, publicdashboardStore, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, publicdashboardStore, fakeDashboardService, nil)
|
||||
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
@ -932,7 +942,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
|
||||
t.Run("Validate pubdash has default share value", func(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
@ -970,7 +980,7 @@ func assertFalseIfNull(t *testing.T, expectedValue bool, nullableValue *bool) {
|
||||
|
||||
func TestUpdatePublicDashboard(t *testing.T) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
@ -1153,7 +1163,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
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) {
|
||||
fakeDashboardService := &dashboards.FakeDashboardService{}
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, fakeDashboardService, nil)
|
||||
service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil)
|
||||
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotaService)
|
||||
@ -1273,7 +1283,7 @@ func TestDeletePublicDashboard(t *testing.T) {
|
||||
if tt.ExpectedErrResp == nil || tt.mockDeleteStore.StoreRespErr != nil {
|
||||
store.On("Delete", mock.Anything, mock.Anything).Return(tt.mockDeleteStore.AffectedRowsResp, tt.mockDeleteStore.StoreRespErr)
|
||||
}
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, store, nil, nil)
|
||||
service, _, _ := newPublicDashboardServiceImpl(t, nil, nil, store, nil, nil)
|
||||
|
||||
err := service.Delete(context.Background(), "pubdashUID", "uid")
|
||||
if tt.ExpectedErrResp != nil {
|
||||
@ -1385,29 +1395,289 @@ func TestDashboardEnabledChanged(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||
features := featuremgmt.WithFeatures()
|
||||
testDB, cfg := db.InitTestDBWithCfg(t)
|
||||
dashStore, err := dashboardsDB.ProvideDashboardStore(testDB, cfg, features, tagimpl.ProvideService(testDB), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
ac := acmock.New()
|
||||
|
||||
fStore := folderimpl.ProvideStore(testDB)
|
||||
folderPermissions := acmock.NewMockedPermissionsService()
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(testDB)
|
||||
folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, folderStore, testDB, features, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest())
|
||||
|
||||
dashboardService, err := dashsvc.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), folderPermissions, &actest.FakePermissionsService{}, ac, folderSvc, fStore, nil, zanzana.NewNoopClient(), nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
fakeGuardian := &guardian.FakeDashboardGuardian{
|
||||
CanSaveValue: true,
|
||||
CanEditUIDs: []string{},
|
||||
CanViewUIDs: []string{},
|
||||
}
|
||||
guardian.MockDashboardGuardian(fakeGuardian)
|
||||
|
||||
// insert in test data so we can check that permissions are working properly through the dashboard service
|
||||
// this will create 4 dashboards and 3 users
|
||||
// user1 has access to all dashboards ("*")
|
||||
// user2 has access to solely one dashboard
|
||||
// user3 has access to all created dashboards through specific permissions
|
||||
creatingUser := &user.SignedInUser{
|
||||
UserID: 1,
|
||||
OrgID: 1,
|
||||
OrgRole: org.RoleAdmin,
|
||||
}
|
||||
dashboardsToSave := []dashboards.SaveDashboardDTO{
|
||||
{
|
||||
OrgID: 1,
|
||||
User: creatingUser,
|
||||
Dashboard: &dashboards.Dashboard{
|
||||
OrgID: 1,
|
||||
UID: "9S6TmO67z",
|
||||
Title: "test",
|
||||
Slug: "test",
|
||||
Data: simplejson.New(),
|
||||
},
|
||||
},
|
||||
{
|
||||
OrgID: 1,
|
||||
User: creatingUser,
|
||||
Dashboard: &dashboards.Dashboard{
|
||||
OrgID: 1,
|
||||
UID: "1S6TmO67z",
|
||||
Title: "my first dashboard",
|
||||
Slug: "my-first-dashboard",
|
||||
Data: simplejson.New(),
|
||||
},
|
||||
},
|
||||
{
|
||||
OrgID: 1,
|
||||
User: creatingUser,
|
||||
Dashboard: &dashboards.Dashboard{
|
||||
OrgID: 1,
|
||||
UID: "2S6TmO67z",
|
||||
Title: "my second dashboard",
|
||||
Slug: "my-second-dashboard",
|
||||
Data: simplejson.New(),
|
||||
},
|
||||
},
|
||||
{
|
||||
OrgID: 1,
|
||||
User: creatingUser,
|
||||
Dashboard: &dashboards.Dashboard{
|
||||
OrgID: 1,
|
||||
UID: "0S6TmO67z",
|
||||
Title: "my zero dashboard",
|
||||
Slug: "my-zero-dashboard",
|
||||
Data: simplejson.New(),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, dash := range dashboardsToSave {
|
||||
_, err = dashboardService.SaveDashboard(context.Background(), &dash, true)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
users := []user.User{
|
||||
{
|
||||
ID: 1,
|
||||
UID: "user1",
|
||||
Email: "test1@gmail.com",
|
||||
Login: "user1",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
UID: "user2",
|
||||
Login: "user2",
|
||||
Email: "test2@gmail.com",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
UID: "user3",
|
||||
Login: "user3",
|
||||
Email: "test3@gmail.com",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
}
|
||||
roles := []accesscontrol.Role{
|
||||
{
|
||||
ID: 1,
|
||||
UID: "role1",
|
||||
Name: "forUser1",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
UID: "role2",
|
||||
Name: "forUser2",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
UID: "role3",
|
||||
Name: "forUser3",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
}
|
||||
|
||||
userRoles := []accesscontrol.UserRole{
|
||||
{
|
||||
ID: 1,
|
||||
OrgID: 1,
|
||||
UserID: 1,
|
||||
RoleID: 1,
|
||||
Created: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
OrgID: 1,
|
||||
UserID: 2,
|
||||
RoleID: 2,
|
||||
Created: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
OrgID: 1,
|
||||
UserID: 3,
|
||||
RoleID: 3,
|
||||
Created: time.Now(),
|
||||
},
|
||||
}
|
||||
|
||||
permissions := []accesscontrol.Permission{
|
||||
{
|
||||
ID: 1,
|
||||
RoleID: 1,
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "*",
|
||||
Kind: "dashboards",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
RoleID: 2,
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "dashboards:uid:1S6TmO67z",
|
||||
Attribute: "uid",
|
||||
Identifier: "1S6TmO67z",
|
||||
Kind: "dashboards",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
RoleID: 3,
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "dashboards:uid:0S6TmO67z",
|
||||
Identifier: "0S6TmO67z",
|
||||
Attribute: "uid",
|
||||
Kind: "dashboards",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 4,
|
||||
RoleID: 3,
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "dashboards:uid:1S6TmO67z",
|
||||
Identifier: "1S6TmO67z",
|
||||
Kind: "dashboards",
|
||||
Attribute: "uid",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 5,
|
||||
RoleID: 3,
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "dashboards:uid:2S6TmO67z",
|
||||
Identifier: "2S6TmO67z",
|
||||
Kind: "dashboards",
|
||||
Attribute: "uid",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 6,
|
||||
RoleID: 3,
|
||||
Action: dashboards.ActionDashboardsRead,
|
||||
Scope: "dashboards:uid:9S6TmO67z",
|
||||
Identifier: "9S6TmO67z",
|
||||
Kind: "dashboards",
|
||||
Attribute: "uid",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 7,
|
||||
RoleID: 1,
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: "*",
|
||||
Kind: "folders",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 8,
|
||||
RoleID: 2,
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: "*",
|
||||
Kind: "folders",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
{
|
||||
ID: 9,
|
||||
RoleID: 3,
|
||||
Action: dashboards.ActionFoldersRead,
|
||||
Scope: "*",
|
||||
Kind: "folders",
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
},
|
||||
}
|
||||
|
||||
err = testDB.WithDbSession(context.Background(), func(sess *db.Session) error {
|
||||
if _, err := sess.Insert(users); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := sess.Insert(roles); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Insert(userRoles); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := sess.Insert(permissions)
|
||||
return err
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
query *PublicDashboardListQuery
|
||||
}
|
||||
|
||||
type mockResponse struct {
|
||||
PublicDashboardListResponseWithPagination *PublicDashboardListResponseWithPagination
|
||||
Err error
|
||||
DashboardResponse []dashboards.DashboardSearchProjection
|
||||
DashboardErr error
|
||||
}
|
||||
|
||||
mockedDashboards := []*PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "0GwW7mgVk",
|
||||
AccessToken: "0b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "0S6TmO67z",
|
||||
Title: "my zero dashboard",
|
||||
IsEnabled: true,
|
||||
},
|
||||
expectedFinalResponse := []*PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "1GwW7mgVk",
|
||||
AccessToken: "1b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "1S6TmO67z",
|
||||
Title: "my first dashboard",
|
||||
Slug: "my-first-dashboard",
|
||||
IsEnabled: true,
|
||||
},
|
||||
{
|
||||
@ -1415,13 +1685,49 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||
AccessToken: "2b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "2S6TmO67z",
|
||||
Title: "my second dashboard",
|
||||
Slug: "my-second-dashboard",
|
||||
IsEnabled: false,
|
||||
},
|
||||
{
|
||||
Uid: "0GwW7mgVk",
|
||||
AccessToken: "0b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "0S6TmO67z",
|
||||
Title: "my zero dashboard",
|
||||
Slug: "my-zero-dashboard",
|
||||
IsEnabled: true,
|
||||
},
|
||||
{
|
||||
Uid: "9GwW7mgVk",
|
||||
AccessToken: "deletedashboardaccesstoken",
|
||||
DashboardUid: "9S6TmO67z",
|
||||
Title: "test",
|
||||
Slug: "test",
|
||||
IsEnabled: true,
|
||||
},
|
||||
}
|
||||
mockedStoreResponse := []*PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "0GwW7mgVk",
|
||||
AccessToken: "0b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "0S6TmO67z",
|
||||
IsEnabled: true,
|
||||
},
|
||||
{
|
||||
Uid: "1GwW7mgVk",
|
||||
AccessToken: "1b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "1S6TmO67z",
|
||||
IsEnabled: true,
|
||||
},
|
||||
{
|
||||
Uid: "2GwW7mgVk",
|
||||
AccessToken: "2b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "2S6TmO67z",
|
||||
IsEnabled: false,
|
||||
},
|
||||
{
|
||||
Uid: "9GwW7mgVk",
|
||||
AccessToken: "deletedashboardaccesstoken",
|
||||
DashboardUid: "9S6TmO67z",
|
||||
Title: "",
|
||||
IsEnabled: true,
|
||||
},
|
||||
}
|
||||
@ -1434,13 +1740,11 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "should return correct pagination response",
|
||||
name: "should return full response when user has access to all dashboards",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
query: &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
||||
},
|
||||
User: &user.SignedInUser{OrgID: 1, UserID: 1, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"*"}, "folders:read": {"*"}}}},
|
||||
OrgID: 1,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
@ -1448,16 +1752,146 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||
},
|
||||
mockResponse: &mockResponse{
|
||||
PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{
|
||||
TotalCount: int64(len(mockedDashboards)),
|
||||
PublicDashboards: mockedDashboards,
|
||||
TotalCount: int64(len(mockedStoreResponse)),
|
||||
PublicDashboards: mockedStoreResponse,
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
want: &PublicDashboardListResponseWithPagination{
|
||||
Page: 1,
|
||||
PerPage: 50,
|
||||
TotalCount: int64(len(mockedDashboards)),
|
||||
PublicDashboards: mockedDashboards,
|
||||
TotalCount: int64(len(expectedFinalResponse)),
|
||||
PublicDashboards: expectedFinalResponse,
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should only return the one dashboard user 2 has access to",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
query: &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{OrgID: 1, UserID: 2, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"dashboards:uid:1S6TmO67z"}, "folders:read": {"*"}}}},
|
||||
OrgID: 1,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
},
|
||||
},
|
||||
mockResponse: &mockResponse{
|
||||
PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{
|
||||
TotalCount: int64(len(mockedStoreResponse)),
|
||||
PublicDashboards: mockedStoreResponse,
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
want: &PublicDashboardListResponseWithPagination{
|
||||
Page: 1,
|
||||
PerPage: 50,
|
||||
TotalCount: 1,
|
||||
PublicDashboards: []*PublicDashboardListResponse{expectedFinalResponse[0]},
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should return full response when user 3 has specific access to all dashboards",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
query: &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{OrgID: 1, UserID: 3, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"dashboards:uid:0S6TmO67z", "dashboards:uid:1S6TmO67z", "dashboards:uid:2S6TmO67z", "dashboards:uid:9S6TmO67z"}, "folders:read": {"*"}}}},
|
||||
OrgID: 1,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
},
|
||||
},
|
||||
mockResponse: &mockResponse{
|
||||
PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{
|
||||
TotalCount: int64(len(mockedStoreResponse)),
|
||||
PublicDashboards: mockedStoreResponse,
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
want: &PublicDashboardListResponseWithPagination{
|
||||
Page: 1,
|
||||
PerPage: 50,
|
||||
TotalCount: int64(len(expectedFinalResponse)),
|
||||
PublicDashboards: expectedFinalResponse,
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should an empty response for a user with no access",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
query: &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{OrgID: 1, UserID: 4, Permissions: map[int64]map[string][]string{}},
|
||||
OrgID: 1,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
},
|
||||
},
|
||||
mockResponse: &mockResponse{
|
||||
PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{
|
||||
TotalCount: int64(len(mockedStoreResponse)),
|
||||
PublicDashboards: mockedStoreResponse,
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
want: &PublicDashboardListResponseWithPagination{
|
||||
Page: 1,
|
||||
PerPage: 50,
|
||||
TotalCount: 0,
|
||||
PublicDashboards: []*PublicDashboardListResponse{},
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should return correct pagination response if limited",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
query: &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{OrgID: 1, UserID: 1, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"*"}, "folders:read": {"*"}}}},
|
||||
OrgID: 1,
|
||||
Page: 1,
|
||||
Limit: 2,
|
||||
},
|
||||
},
|
||||
mockResponse: &mockResponse{
|
||||
PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{
|
||||
TotalCount: int64(len(mockedStoreResponse)),
|
||||
PublicDashboards: mockedStoreResponse,
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
want: &PublicDashboardListResponseWithPagination{
|
||||
Page: 1,
|
||||
PerPage: 2,
|
||||
TotalCount: 4,
|
||||
PublicDashboards: expectedFinalResponse[:2],
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should return correct page",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
query: &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{OrgID: 1, UserID: 1, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"*"}, "folders:read": {"*"}}}},
|
||||
OrgID: 1,
|
||||
Page: 2,
|
||||
Limit: 2,
|
||||
},
|
||||
},
|
||||
mockResponse: &mockResponse{
|
||||
PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{
|
||||
TotalCount: int64(len(mockedStoreResponse)),
|
||||
PublicDashboards: mockedStoreResponse,
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
want: &PublicDashboardListResponseWithPagination{
|
||||
Page: 2,
|
||||
PerPage: 2,
|
||||
TotalCount: 4,
|
||||
PublicDashboards: expectedFinalResponse[2:],
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
@ -1483,14 +1917,12 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient())
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
store := NewFakePublicDashboardStore(t)
|
||||
store.On("FindAllWithPagination", mock.Anything, mock.Anything).
|
||||
store.On("FindAll", mock.Anything, mock.Anything).
|
||||
Return(tt.mockResponse.PublicDashboardListResponseWithPagination, tt.mockResponse.Err)
|
||||
pd, _, _ := newPublicDashboardServiceImpl(t, store, nil, nil)
|
||||
pd, _, _ := newPublicDashboardServiceImpl(t, testDB, cfg, store, dashboardService, nil)
|
||||
pd.ac = ac
|
||||
|
||||
got, err := pd.FindAllWithPagination(tt.args.ctx, tt.args.query)
|
||||
|
Loading…
Reference in New Issue
Block a user