diff --git a/pkg/api/dashboard_permission_test.go b/pkg/api/dashboard_permission_test.go index 7bbfe2e481e..5b28f1352df 100644 --- a/pkg/api/dashboard_permission_test.go +++ b/pkg/api/dashboard_permission_test.go @@ -47,7 +47,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) { SQLStore: mockSQLStore, Features: features, DashboardService: dashboardservice.ProvideDashboardService( - settings, dashboardStore, foldertest.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac, + settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac, folderSvc, ), AccessControl: accesscontrolmock.New().WithDisabled(), diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index 56f94432fec..b79b4a6945c 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -982,13 +982,13 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr dashboardPermissions := accesscontrolmock.NewMockedPermissionsService() features := featuremgmt.WithFeatures() - folderSvc := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), cfg, dashboardStore, folderStore, db.InitTestDB(t), featuremgmt.WithFeatures()) + folderSvc := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), + cfg, dashboardStore, folderStore, db.InitTestDB(t), featuremgmt.WithFeatures()) if dashboardService == nil { dashboardService = service.ProvideDashboardService( - cfg, dashboardStore, folderStore, nil, features, - folderPermissions, dashboardPermissions, ac, - folderSvc, + cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions, + ac, folderSvc, ) } @@ -1000,9 +1000,8 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr ProvisioningService: provisioningService, AccessControl: accesscontrolmock.New(), dashboardProvisioningService: service.ProvideDashboardService( - cfg, dashboardStore, folderStore, nil, features, - folderPermissions, dashboardPermissions, ac, - folderSvc, + cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions, + ac, folderSvc, ), DashboardService: dashboardService, Features: featuremgmt.WithFeatures(), diff --git a/pkg/api/folder_permission_test.go b/pkg/api/folder_permission_test.go index 9f2190aa1f0..371242d1c59 100644 --- a/pkg/api/folder_permission_test.go +++ b/pkg/api/folder_permission_test.go @@ -45,7 +45,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) { folderPermissionsService: folderPermissions, dashboardPermissionsService: dashboardPermissions, DashboardService: service.ProvideDashboardService( - settings, dashboardStore, foldertest.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac, + settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac, folderService, ), AccessControl: accesscontrolmock.New().WithDisabled(), diff --git a/pkg/services/dashboards/accesscontrol.go b/pkg/services/dashboards/accesscontrol.go index d01f9d719cf..d1b314adc89 100644 --- a/pkg/services/dashboards/accesscontrol.go +++ b/pkg/services/dashboards/accesscontrol.go @@ -39,7 +39,7 @@ var ( ) // NewFolderNameScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope. -func NewFolderNameScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewFolderNameScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScopeName("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { if !strings.HasPrefix(scope, prefix) { @@ -49,7 +49,7 @@ func NewFolderNameScopeResolver(db Store, folderDB folder.FolderStore, folderSvc if len(nsName) == 0 { return nil, ac.ErrInvalidScope } - folder, err := folderDB.GetFolderByTitle(ctx, orgID, nsName) + folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{Title: &nsName}) if err != nil { return nil, err } @@ -65,7 +65,7 @@ func NewFolderNameScopeResolver(db Store, folderDB folder.FolderStore, folderSvc } // NewFolderIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:id:" into an uid based scope. -func NewFolderIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewFolderIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScope("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { if !strings.HasPrefix(scope, prefix) { @@ -81,7 +81,7 @@ func NewFolderIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc f return []string{ScopeFoldersProvider.GetResourceScopeUID(ac.GeneralFolderUID)}, nil } - folder, err := folderDB.GetFolderByID(ctx, orgID, id) + folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{OrgID: orgID, ID: &id}) if err != nil { return nil, err } @@ -98,7 +98,7 @@ func NewFolderIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc f // NewFolderUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:uid:" // into uid based scopes for folder and its parents -func NewFolderUIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScopeUID("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { if !strings.HasPrefix(scope, prefix) { @@ -120,7 +120,7 @@ func NewFolderUIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc // NewDashboardIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:id:" // into uid based scopes for both dashboard and folder -func NewDashboardIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewDashboardIDScopeResolver(ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeDashboardsProvider.GetResourceScope("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { if !strings.HasPrefix(scope, prefix) { @@ -132,18 +132,18 @@ func NewDashboardIDScopeResolver(db Store, folderDB folder.FolderStore, folderSv return nil, err } - dashboard, err := db.GetDashboard(ctx, &GetDashboardQuery{ID: id, OrgID: orgID}) + dashboard, err := ds.GetDashboard(ctx, &GetDashboardQuery{ID: id, OrgID: orgID}) if err != nil { return nil, err } - return resolveDashboardScope(ctx, db, folderDB, orgID, dashboard, folderSvc) + return resolveDashboardScope(ctx, orgID, dashboard, folderSvc) }) } // NewDashboardUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:uid:" // into uid based scopes for both dashboard and folder -func NewDashboardUIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { +func NewDashboardUIDScopeResolver(ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeDashboardsProvider.GetResourceScopeUID("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { if !strings.HasPrefix(scope, prefix) { @@ -155,16 +155,16 @@ func NewDashboardUIDScopeResolver(db Store, folderDB folder.FolderStore, folderS return nil, err } - dashboard, err := db.GetDashboard(ctx, &GetDashboardQuery{UID: uid, OrgID: orgID}) + dashboard, err := ds.GetDashboard(ctx, &GetDashboardQuery{UID: uid, OrgID: orgID}) if err != nil { return nil, err } - return resolveDashboardScope(ctx, db, folderDB, orgID, dashboard, folderSvc) + return resolveDashboardScope(ctx, orgID, dashboard, folderSvc) }) } -func resolveDashboardScope(ctx context.Context, db Store, folderDB folder.FolderStore, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) { +func resolveDashboardScope(ctx context.Context, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) { var folderUID string if dashboard.FolderID < 0 { return []string{ScopeDashboardsProvider.GetResourceScopeUID(dashboard.UID)}, nil @@ -173,7 +173,7 @@ func resolveDashboardScope(ctx context.Context, db Store, folderDB folder.Folder if dashboard.FolderID == 0 { folderUID = ac.GeneralFolderUID } else { - folder, err := folderDB.GetFolderByID(ctx, orgID, dashboard.FolderID) + folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{OrgID: orgID, ID: &dashboard.FolderID}) if err != nil { return nil, err } diff --git a/pkg/services/dashboards/accesscontrol_test.go b/pkg/services/dashboards/accesscontrol_test.go index 1410cc7381a..87f63133b6c 100644 --- a/pkg/services/dashboards/accesscontrol_test.go +++ b/pkg/services/dashboards/accesscontrol_test.go @@ -19,43 +19,30 @@ import ( func TestNewFolderNameScopeResolver(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) { - prefix, _ := NewFolderNameScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + prefix, _ := NewFolderNameScopeResolver(foldertest.NewFakeService()) require.Equal(t, "folders:name:", prefix) }) t.Run("resolver should convert to uid scope", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} + folderService := foldertest.NewFakeService() orgId := rand.Int63() title := "Very complex :title with: and /" + util.GenerateShortUID() - db := &folder.Folder{Title: title, ID: rand.Int63(), UID: util.GenerateShortUID()} - - folderStore := foldertest.NewFakeFolderStore(t) - folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once() + folderService.ExpectedFolder = db scope := "folders:name:" + title - _, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService()) - + _, resolver := NewFolderNameScopeResolver(folderService) resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) require.NoError(t, err) require.Len(t, resolvedScopes, 1) - require.Equal(t, fmt.Sprintf("folders:uid:%v", db.UID), resolvedScopes[0]) - - folderStore.AssertCalled(t, "GetFolderByTitle", mock.Anything, orgId, title) }) t.Run("resolver should include inherited scopes if any", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} orgId := rand.Int63() title := "Very complex :title with: and /" + util.GenerateShortUID() - - db := &folder.Folder{Title: title, ID: rand.Int63(), UID: util.GenerateShortUID()} - - folderStore := foldertest.NewFakeFolderStore(t) - folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once() - scope := "folders:name:" + title + uid := util.GenerateShortUID() folderSvc := foldertest.NewFakeService() folderSvc.ExpectedFolders = []*folder.Folder{ @@ -66,44 +53,39 @@ func TestNewFolderNameScopeResolver(t *testing.T) { UID: "grandparent", }, } - _, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, folderSvc) + folderSvc.ExpectedFolder = &folder.Folder{Title: title, ID: rand.Int63(), UID: uid} + _, resolver := NewFolderNameScopeResolver(folderSvc) resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) require.NoError(t, err) require.Len(t, resolvedScopes, 3) if diff := cmp.Diff([]string{ - fmt.Sprintf("folders:uid:%v", db.UID), + fmt.Sprintf("folders:uid:%v", uid), "folders:uid:parent", "folders:uid:grandparent", }, resolvedScopes); diff != "" { t.Errorf("Result mismatch (-want +got):\n%s", diff) } - - folderStore.AssertCalled(t, "GetFolderByTitle", mock.Anything, orgId, title) }) t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} - _, resolver := NewFolderNameScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewFolderNameScopeResolver(foldertest.NewFakeService()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:123") require.ErrorIs(t, err, ac.ErrInvalidScope) }) t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} - _, resolver := NewFolderNameScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewFolderNameScopeResolver(foldertest.NewFakeService()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:name:") require.ErrorIs(t, err, ac.ErrInvalidScope) }) t.Run("returns 'not found' if folder does not exist", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} - - folderStore := foldertest.NewFakeFolderStore(t) - _, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService()) + folderService := foldertest.NewFakeService() + _, resolver := NewFolderNameScopeResolver(folderService) orgId := rand.Int63() - folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once() + folderService.ExpectedError = ErrDashboardNotFound scope := "folders:name:" + util.GenerateShortUID() @@ -115,35 +97,26 @@ func TestNewFolderNameScopeResolver(t *testing.T) { func TestNewFolderIDScopeResolver(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) { - prefix, _ := NewFolderIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + prefix, _ := NewFolderIDScopeResolver(foldertest.NewFakeService()) require.Equal(t, "folders:id:", prefix) }) t.Run("resolver should convert to uid scope", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} - folderStore := foldertest.NewFakeFolderStore(t) - - _, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService()) - + folderSvc := foldertest.NewFakeService() orgId := rand.Int63() uid := util.GenerateShortUID() - db := &folder.Folder{ID: rand.Int63(), UID: uid} - folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once() + folderSvc.ExpectedFolder = db + + _, resolver := NewFolderIDScopeResolver(folderSvc) scope := "folders:id:" + strconv.FormatInt(db.ID, 10) - resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) require.NoError(t, err) require.Len(t, resolvedScopes, 1) require.Equal(t, fmt.Sprintf("folders:uid:%v", db.UID), resolvedScopes[0]) - - folderStore.AssertCalled(t, "GetFolderByID", mock.Anything, orgId, db.ID) }) t.Run("resolver should should include inherited scopes if any", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} - folderStore := foldertest.NewFakeFolderStore(t) - folderSvc := foldertest.NewFakeService() folderSvc.ExpectedFolders = []*folder.Folder{ { @@ -153,13 +126,12 @@ func TestNewFolderIDScopeResolver(t *testing.T) { UID: "grandparent", }, } - _, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, folderSvc) + _, resolver := NewFolderIDScopeResolver(folderSvc) orgId := rand.Int63() uid := util.GenerateShortUID() - db := &folder.Folder{ID: rand.Int63(), UID: uid} - folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once() + folderSvc.ExpectedFolder = db scope := "folders:id:" + strconv.FormatInt(db.ID, 10) @@ -174,12 +146,9 @@ func TestNewFolderIDScopeResolver(t *testing.T) { }, resolvedScopes); diff != "" { t.Errorf("Result mismatch (-want +got):\n%s", diff) } - - folderStore.AssertCalled(t, "GetFolderByID", mock.Anything, orgId, db.ID) }) t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} - _, resolver := NewFolderIDScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewFolderIDScopeResolver(foldertest.NewFakeService()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:uid:123") require.ErrorIs(t, err, ac.ErrInvalidScope) @@ -187,10 +156,9 @@ func TestNewFolderIDScopeResolver(t *testing.T) { t.Run("resolver should convert id 0 to general uid scope", func(t *testing.T) { var ( - dashboardStore = &FakeDashboardStore{} - orgId = rand.Int63() - scope = "folders:id:0" - _, resolver = NewFolderIDScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + orgId = rand.Int63() + scope = "folders:id:0" + _, resolver = NewFolderIDScopeResolver(foldertest.NewFakeService()) ) resolved, err := resolver.Resolve(context.Background(), orgId, scope) @@ -201,20 +169,17 @@ func TestNewFolderIDScopeResolver(t *testing.T) { }) t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} - _, resolver := NewFolderIDScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewFolderIDScopeResolver(foldertest.NewFakeService()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:") require.ErrorIs(t, err, ac.ErrInvalidScope) }) t.Run("returns 'not found' if folder does not exist", func(t *testing.T) { - dashboardStore := &FakeDashboardStore{} - folderStore := foldertest.NewFakeFolderStore(t) - - _, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService()) + svc := foldertest.NewFakeService() + svc.ExpectedError = ErrDashboardNotFound + _, resolver := NewFolderIDScopeResolver(svc) orgId := rand.Int63() - folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once() scope := "folders:id:10" resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) @@ -225,22 +190,21 @@ func TestNewFolderIDScopeResolver(t *testing.T) { func TestNewDashboardIDScopeResolver(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) { - prefix, _ := NewDashboardIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + prefix, _ := NewDashboardIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService()) require.Equal(t, "dashboards:id:", prefix) }) t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) { - store := &FakeDashboardStore{} - folderStore := foldertest.NewFakeFolderStore(t) - - _, resolver := NewDashboardIDScopeResolver(store, folderStore, foldertest.NewFakeService()) + dashSvc := NewFakeDashboardService(t) + folderService := foldertest.NewFakeService() + _, resolver := NewDashboardIDScopeResolver(dashSvc, folderService) orgID := rand.Int63() folder := &folder.Folder{ID: 2, UID: "2"} dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"} - store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() - folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once() + dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() + folderService.ExpectedFolder = folder scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10)) resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope) @@ -251,9 +215,7 @@ func TestNewDashboardIDScopeResolver(t *testing.T) { }) t.Run("resolver should inlude inherited scopes if any", func(t *testing.T) { - store := &FakeDashboardStore{} - folderStore := foldertest.NewFakeFolderStore(t) - + dashSvc := &FakeDashboardService{} folderSvc := foldertest.NewFakeService() folderSvc.ExpectedFolders = []*folder.Folder{ { @@ -263,14 +225,13 @@ func TestNewDashboardIDScopeResolver(t *testing.T) { UID: "grandparent", }, } - _, resolver := NewDashboardIDScopeResolver(store, folderStore, folderSvc) + _, resolver := NewDashboardIDScopeResolver(dashSvc, folderSvc) orgID := rand.Int63() folder := &folder.Folder{ID: 2, UID: "2"} dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"} - - store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() - folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once() + folderSvc.ExpectedFolder = folder + dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10)) resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope) @@ -288,17 +249,17 @@ func TestNewDashboardIDScopeResolver(t *testing.T) { }) t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { - _, resolver := NewDashboardIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewDashboardIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:uid:123") require.ErrorIs(t, err, ac.ErrInvalidScope) }) t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) { - store := &FakeDashboardStore{} - _, resolver := NewDashboardIDScopeResolver(store, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + dashSvc := &FakeDashboardService{} + _, resolver := NewDashboardIDScopeResolver(dashSvc, foldertest.NewFakeService()) dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"} - store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil) + dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil) resolved, err := resolver.Resolve(context.Background(), 1, ac.Scope("dashboards", "id", "1")) require.NoError(t, err) @@ -310,21 +271,20 @@ func TestNewDashboardIDScopeResolver(t *testing.T) { func TestNewDashboardUIDScopeResolver(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) { - prefix, _ := NewDashboardUIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + prefix, _ := NewDashboardUIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService()) require.Equal(t, "dashboards:uid:", prefix) }) t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) { - store := &FakeDashboardStore{} - folderStore := foldertest.NewFakeFolderStore(t) - _, resolver := NewDashboardUIDScopeResolver(store, folderStore, foldertest.NewFakeService()) + service := &FakeDashboardService{} + folderSvc := foldertest.NewFakeService() + _, resolver := NewDashboardUIDScopeResolver(service, folderSvc) orgID := rand.Int63() folder := &folder.Folder{ID: 2, UID: "2"} + folderSvc.ExpectedFolder = folder dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"} - - store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() - folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once() + service.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() scope := ac.Scope("dashboards", "uid", dashboard.UID) resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope) @@ -335,9 +295,7 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) { }) t.Run("resolver should include inherited scopes if any", func(t *testing.T) { - store := &FakeDashboardStore{} - folderStore := foldertest.NewFakeFolderStore(t) - + svc := &FakeDashboardService{} folderSvc := foldertest.NewFakeService() folderSvc.ExpectedFolders = []*folder.Folder{ { @@ -348,14 +306,13 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) { }, } - _, resolver := NewDashboardUIDScopeResolver(store, folderStore, folderSvc) + _, resolver := NewDashboardUIDScopeResolver(svc, folderSvc) orgID := rand.Int63() folder := &folder.Folder{ID: 2, UID: "2"} + folderSvc.ExpectedFolder = folder dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"} - - store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() - folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once() + svc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() scope := ac.Scope("dashboards", "uid", dashboard.UID) resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope) @@ -373,17 +330,17 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) { }) t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { - _, resolver := NewDashboardUIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + _, resolver := NewDashboardUIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService()) _, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:id:123") require.ErrorIs(t, err, ac.ErrInvalidScope) }) t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) { - store := &FakeDashboardStore{} - _, resolver := NewDashboardUIDScopeResolver(store, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) + service := &FakeDashboardService{} + _, resolver := NewDashboardUIDScopeResolver(service, foldertest.NewFakeService()) dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"} - store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil) + service.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil) resolved, err := resolver.Resolve(context.Background(), 1, ac.Scope("dashboards", "uid", "1")) require.NoError(t, err) diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 6dba87c13af..95fc5a9ae73 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -40,7 +40,7 @@ type DashboardServiceImpl struct { cfg *setting.Cfg log log.Logger dashboardStore dashboards.Store - folderStore folder.FolderStore + folderService folder.Service dashAlertExtractor alerting.DashAlertExtractor features featuremgmt.FeatureToggles folderPermissions accesscontrol.FolderPermissionsService @@ -50,15 +50,12 @@ type DashboardServiceImpl struct { // This is the uber service that implements a three smaller services func ProvideDashboardService( - cfg *setting.Cfg, dashboardStore dashboards.Store, folderStore folder.FolderStore, dashAlertExtractor alerting.DashAlertExtractor, + cfg *setting.Cfg, dashboardStore dashboards.Store, dashAlertExtractor alerting.DashAlertExtractor, features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService, ac accesscontrol.AccessControl, folderSvc folder.Service, ) *DashboardServiceImpl { - ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(dashboardStore, folderStore, folderSvc)) - ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashboardStore, folderStore, folderSvc)) - - return &DashboardServiceImpl{ + dashSvc := &DashboardServiceImpl{ cfg: cfg, log: log.New("dashboard-service"), dashboardStore: dashboardStore, @@ -67,7 +64,13 @@ func ProvideDashboardService( folderPermissions: folderPermissionsService, dashboardPermissions: dashboardPermissionsService, ac: ac, + folderService: folderSvc, } + + ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(dashSvc, folderSvc)) + ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashSvc, folderSvc)) + + return dashSvc } func (dr *DashboardServiceImpl) GetProvisionedDashboardData(ctx context.Context, name string) ([]*dashboards.DashboardProvisioning, error) { @@ -628,7 +631,7 @@ func (dr DashboardServiceImpl) CountDashboardsInFolder(ctx context.Context, quer return 0, err } - folder, err := dr.folderStore.GetFolderByUID(ctx, u.OrgID, query.FolderUID) + folder, err := dr.folderService.Get(ctx, &folder.GetFolderQuery{UID: &query.FolderUID, OrgID: u.OrgID}) if err != nil { return 0, err } diff --git a/pkg/services/dashboards/service/dashboard_service_integration_test.go b/pkg/services/dashboards/service/dashboard_service_integration_test.go index f91ffbe27c3..33059f97ad5 100644 --- a/pkg/services/dashboards/service/dashboard_service_integration_test.go +++ b/pkg/services/dashboards/service/dashboard_service_integration_test.go @@ -15,7 +15,6 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder/folderimpl" "github.com/grafana/grafana/pkg/services/folder/foldertest" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/org" @@ -827,9 +826,8 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc quotaService := quotatest.New(false, nil) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) service := ProvideDashboardService( - cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, + cfg, dashboardStore, &dummyDashAlertExtractor{}, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), @@ -888,9 +886,8 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt quotaService := quotatest.New(false, nil) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) service := ProvideDashboardService( - cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, + cfg, dashboardStore, &dummyDashAlertExtractor{}, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), @@ -911,9 +908,8 @@ func callSaveWithError(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSto quotaService := quotatest.New(false, nil) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) service := ProvideDashboardService( - cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, + cfg, dashboardStore, &dummyDashAlertExtractor{}, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), @@ -952,9 +948,8 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto quotaService := quotatest.New(false, nil) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) service := ProvideDashboardService( - cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, + cfg, dashboardStore, &dummyDashAlertExtractor{}, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), @@ -994,9 +989,8 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da quotaService := quotatest.New(false, nil) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) service := ProvideDashboardService( - cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, + cfg, dashboardStore, &dummyDashAlertExtractor{}, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), diff --git a/pkg/services/dashboards/service/dashboard_service_test.go b/pkg/services/dashboards/service/dashboard_service_test.go index 853ec701bbe..6e2ce1377ed 100644 --- a/pkg/services/dashboards/service/dashboard_service_test.go +++ b/pkg/services/dashboards/service/dashboard_service_test.go @@ -25,13 +25,13 @@ func TestDashboardService(t *testing.T) { fakeStore := dashboards.FakeDashboardStore{} defer fakeStore.AssertExpectations(t) - folderStore := foldertest.NewFakeFolderStore(t) + folderSvc := foldertest.NewFakeService() service := &DashboardServiceImpl{ cfg: setting.NewCfg(), log: log.New("test.logger"), dashboardStore: &fakeStore, - folderStore: folderStore, + folderService: folderSvc, dashAlertExtractor: &dummyDashAlertExtractor{}, } @@ -230,13 +230,11 @@ func TestDashboardService(t *testing.T) { }) t.Run("Count dashboards in folder", func(t *testing.T) { - folderStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(&folder.Folder{}, nil) fakeStore.On("CountDashboardsInFolder", mock.Anything, mock.AnythingOfType("*dashboards.CountDashboardsInFolderRequest")).Return(int64(3), nil) - + folderSvc.ExpectedFolder = &folder.Folder{ID: 1} // set up a ctx with signed in user - ctx := context.Background() usr := &user.SignedInUser{UserID: 1} - ctx = appcontext.WithUser(ctx, usr) + ctx := appcontext.WithUser(context.Background(), usr) count, err := service.CountDashboardsInFolder(ctx, &dashboards.CountDashboardsInFolderQuery{FolderUID: "i am a folder"}) require.NoError(t, err) diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index ee6bd68c705..5463a28b744 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -62,9 +62,9 @@ func ProvideService( srv.DBMigration(db) } - ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore, folderStore, srv)) - ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore, folderStore, srv)) - ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(dashboardStore, folderStore, srv)) + ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(srv)) + ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(srv)) + ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(srv)) return srv } diff --git a/pkg/services/guardian/accesscontrol_guardian_test.go b/pkg/services/guardian/accesscontrol_guardian_test.go index 7face49461f..a9af4ff18eb 100644 --- a/pkg/services/guardian/accesscontrol_guardian_test.go +++ b/pkg/services/guardian/accesscontrol_guardian_test.go @@ -602,21 +602,6 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce OrgID: 1, }) require.NoError(t, err) - ac := accesscontrolmock.New().WithPermissions(permissions) - // TODO replace with actual folder store implementation after resolving import cycles - ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())) - license := licensingtest.NewFakeLicensing() - license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe() - teamSvc := teamimpl.ProvideService(store, store.Cfg) - userSvc, err := userimpl.ProvideService(store, nil, store.Cfg, nil, nil, quotatest.New(false, nil), supportbundlestest.NewFakeBundleService()) - require.NoError(t, err) - - folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions( - setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc) - require.NoError(t, err) - dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions( - setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc) - require.NoError(t, err) if dashboardSvc == nil { fakeDashboardService := dashboards.NewFakeDashboardService(t) qResult := &dashboards.Dashboard{} @@ -631,6 +616,22 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce dashboardSvc = fakeDashboardService } + ac := accesscontrolmock.New().WithPermissions(permissions) + // TODO replace with actual folder store implementation after resolving import cycles + ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashboardSvc, foldertest.NewFakeService())) + license := licensingtest.NewFakeLicensing() + license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe() + teamSvc := teamimpl.ProvideService(store, store.Cfg) + userSvc, err := userimpl.ProvideService(store, nil, store.Cfg, nil, nil, quotatest.New(false, nil), supportbundlestest.NewFakeBundleService()) + require.NoError(t, err) + + folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions( + setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc) + require.NoError(t, err) + dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions( + setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc) + require.NoError(t, err) + g, err := NewAccessControlDashboardGuardian(context.Background(), dash.ID, &user.SignedInUser{OrgID: 1}, store, ac, folderPermissions, dashboardPermissions, dashboardSvc) require.NoError(t, err) g.dashboard = dash @@ -639,7 +640,7 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce func testDashSvc(t *testing.T) dashboards.DashboardService { dashSvc := dashboards.NewFakeDashboardService(t) - var d *dashboards.Dashboard + d := &dashboards.Dashboard{} dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Run(func(args mock.Arguments) { d := dashboards.NewDashboard("mocked") d.ID = 1 diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index 516484efe7f..91097c89ff8 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -294,9 +294,8 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash ac := acmock.New() folderPermissions := acmock.NewMockedPermissionsService() dashboardPermissions := acmock.NewMockedPermissionsService() - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) service := dashboardservice.ProvideDashboardService( - cfg, dashboardStore, folderStore, dashAlertExtractor, + cfg, dashboardStore, dashAlertExtractor, features, folderPermissions, dashboardPermissions, ac, foldertest.NewFakeService(), ) @@ -442,7 +441,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo dashboardPermissions := acmock.NewMockedPermissionsService() folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) dashboardService := dashboardservice.ProvideDashboardService( - sqlStore.Cfg, dashboardStore, folderStore, nil, + sqlStore.Cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac, foldertest.NewFakeService(), ) diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index 57451f99261..e54e64e8c49 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -706,9 +706,8 @@ func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash require.NoError(t, err) dashAlertService := alerting.ProvideDashAlertExtractorService(nil, nil, nil) ac := acmock.New() - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) service := dashboardservice.ProvideDashboardService( - cfg, dashboardStore, folderStore, dashAlertService, + cfg, dashboardStore, dashAlertService, featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), acmock.NewMockedPermissionsService(), ac, foldertest.NewFakeService(), ) diff --git a/pkg/services/ngalert/tests/util.go b/pkg/services/ngalert/tests/util.go index 7c8728a3485..e9bcc9d999c 100644 --- a/pkg/services/ngalert/tests/util.go +++ b/pkg/services/ngalert/tests/util.go @@ -82,7 +82,7 @@ func SetupTestEnv(tb testing.TB, baseInterval time.Duration) (*ngalert.AlertNG, folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) dashboardService := dashboardservice.ProvideDashboardService( - cfg, dashboardStore, folderStore, nil, + cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac, foldertest.NewFakeService(), )