diff --git a/pkg/services/publicdashboards/database/database.go b/pkg/services/publicdashboards/database/database.go index 4e1fee50107..ff606b35437 100644 --- a/pkg/services/publicdashboards/database/database.go +++ b/pkg/services/publicdashboards/database/database.go @@ -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) diff --git a/pkg/services/publicdashboards/database/database_test.go b/pkg/services/publicdashboards/database/database_test.go index d2e506063b1..20bedeeb326 100644 --- a/pkg/services/publicdashboards/database/database_test.go +++ b/pkg/services/publicdashboards/database/database_test.go @@ -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) { diff --git a/pkg/services/publicdashboards/public_dashboard_store_mock.go b/pkg/services/publicdashboards/public_dashboard_store_mock.go index b33c1172a44..ca5a81a02a0 100644 --- a/pkg/services/publicdashboards/public_dashboard_store_mock.go +++ b/pkg/services/publicdashboards/public_dashboard_store_mock.go @@ -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 diff --git a/pkg/services/publicdashboards/publicdashboard.go b/pkg/services/publicdashboards/publicdashboard.go index a0acb6786cf..16ddf157f5b 100644 --- a/pkg/services/publicdashboards/publicdashboard.go +++ b/pkg/services/publicdashboards/publicdashboard.go @@ -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) diff --git a/pkg/services/publicdashboards/service/common_test.go b/pkg/services/publicdashboards/service/common_test.go index fd014362050..4e0acf61c70 100644 --- a/pkg/services/publicdashboards/service/common_test.go +++ b/pkg/services/publicdashboards/service/common_test.go @@ -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 } diff --git a/pkg/services/publicdashboards/service/query_test.go b/pkg/services/publicdashboards/service/query_test.go index ff33e49d609..dfe1712a86b 100644 --- a/pkg/services/publicdashboards/service/query_test.go +++ b/pkg/services/publicdashboards/service/query_test.go @@ -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) diff --git a/pkg/services/publicdashboards/service/service.go b/pkg/services/publicdashboards/service/service.go index 133ebe81e2f..745a660a807 100644 --- a/pkg/services/publicdashboards/service/service.go +++ b/pkg/services/publicdashboards/service/service.go @@ -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 diff --git a/pkg/services/publicdashboards/service/service_test.go b/pkg/services/publicdashboards/service/service_test.go index fa28eed134c..91beeb72021 100644 --- a/pkg/services/publicdashboards/service/service_test.go +++ b/pkg/services/publicdashboards/service/service_test.go @@ -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)