Folders: Split legacy out of folder.Service (and remove folder.FolderStore) (#110734)

This commit is contained in:
Ryan McKinley
2025-09-08 18:27:49 +03:00
committed by GitHub
parent 854a8f7e70
commit 7c95d3c8a9
26 changed files with 99 additions and 332 deletions
+8 -5
View File
@@ -5,10 +5,11 @@ import (
"errors"
"strings"
"go.opentelemetry.io/otel"
"github.com/grafana/grafana/pkg/apimachinery/identity"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/folder"
"go.opentelemetry.io/otel"
)
const (
@@ -45,8 +46,10 @@ var (
tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/dashboards")
)
type UIDLookup = func(ctx context.Context, orgID int64, id int64) (string, error)
// NewFolderIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:id:" into an uid based scope.
func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
func NewFolderIDScopeResolver(lookup UIDLookup, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
prefix := ScopeFoldersProvider.GetResourceScope("")
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
ctx, span := tracer.Start(ctx, "dashboards.NewFolderIDScopeResolver")
@@ -66,17 +69,17 @@ func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Serv
}
return identity.WithServiceIdentityFn(ctx, orgID, func(ctx context.Context) ([]string, error) {
folder, err := folderDB.GetFolderByID(ctx, orgID, id)
uid, err := lookup(ctx, orgID, id)
if err != nil {
return nil, err
}
result, err := GetInheritedScopes(ctx, folder.OrgID, folder.UID, folderSvc)
result, err := GetInheritedScopes(ctx, orgID, uid, folderSvc)
if err != nil {
return nil, err
}
return append([]string{ScopeFoldersProvider.GetResourceScopeUID(folder.UID)}, result...), nil
return append([]string{ScopeFoldersProvider.GetResourceScopeUID(uid)}, result...), nil
})
})
}
+12 -8
View File
@@ -2,24 +2,28 @@ package dashboards
import (
"context"
"fmt"
"math/rand"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/folder/foldertest"
)
func noOpLookup(ctx context.Context, orgID int64, id int64) (string, error) {
return fmt.Sprintf("%d", id), nil
}
func TestNewFolderIDScopeResolver(t *testing.T) {
t.Run("prefix should be expected", func(t *testing.T) {
prefix, _ := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
prefix, _ := NewFolderIDScopeResolver(noOpLookup, foldertest.NewFakeService())
require.Equal(t, "folders:id:", prefix)
})
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
_, resolver := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
_, resolver := NewFolderIDScopeResolver(noOpLookup, foldertest.NewFakeService())
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:uid:123")
require.ErrorIs(t, err, ac.ErrInvalidScope)
@@ -29,7 +33,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
var (
orgId = rand.Int63()
scope = "folders:id:0"
_, resolver = NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
_, resolver = NewFolderIDScopeResolver(noOpLookup, foldertest.NewFakeService())
)
resolved, err := resolver.Resolve(context.Background(), orgId, scope)
@@ -40,15 +44,15 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
})
t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) {
_, resolver := NewFolderIDScopeResolver(foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
_, resolver := NewFolderIDScopeResolver(noOpLookup, 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) {
folderStore := foldertest.NewFakeFolderStore(t)
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
_, resolver := NewFolderIDScopeResolver(folderStore, foldertest.NewFakeService())
_, resolver := NewFolderIDScopeResolver(func(ctx context.Context, orgID int64, id int64) (string, error) {
return "", ErrDashboardNotFound
}, foldertest.NewFakeService())
orgId := rand.Int63()
scope := "folders:id:10"
@@ -83,7 +83,6 @@ type DashboardServiceImpl struct {
cfg *setting.Cfg
log log.Logger
dashboardStore dashboards.Store
folderStore folder.FolderStore
folderService folder.Service
orgService org.Service
features featuremgmt.FeatureToggles
@@ -373,7 +372,6 @@ var _ registry.BackgroundService = (*DashboardServiceImpl)(nil)
func ProvideDashboardServiceImpl(
cfg *setting.Cfg,
dashboardStore dashboards.Store,
folderStore folder.FolderStore,
features featuremgmt.FeatureToggles,
folderPermissionsService accesscontrol.FolderPermissionsService,
ac accesscontrol.AccessControl,
@@ -396,7 +394,6 @@ func ProvideDashboardServiceImpl(
folderPermissions: folderPermissionsService,
ac: ac,
acService: acService,
folderStore: folderStore,
folderService: folderSvc,
orgService: orgService,
k8sclient: k8sClient,
@@ -2094,7 +2094,6 @@ func TestSetDefaultPermissionsAfterCreate(t *testing.T) {
// Setup mocks and service
dashboardStore := &dashboards.FakeDashboardStore{}
folderStore := foldertest.FakeFolderStore{}
features := featuremgmt.WithFeatures()
if tc.featureKubernetesDashboards {
features = featuremgmt.WithFeatures(featuremgmt.FlagKubernetesDashboards)
@@ -2107,7 +2106,6 @@ func TestSetDefaultPermissionsAfterCreate(t *testing.T) {
cfg: setting.NewCfg(),
log: log.New("test-logger"),
dashboardStore: dashboardStore,
folderStore: &folderStore,
features: features,
dashboardPermissions: permService,
folderPermissions: permService,