mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Access control: Modify dashboard/folder resolvers so that return also the inherited scopes (#62025)
* Access Control: Add folder service dependency to the dashboard/folder resolvers * Expose the function fetching parents to folder interface * Add generic prepend utility * Modify dashboard resolvers to return inherited scopes
This commit is contained in:
parent
8e3d22ca7a
commit
cd27562c76
@ -40,6 +40,7 @@ import (
|
|||||||
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||||
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
|
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||||
"github.com/grafana/grafana/pkg/services/guardian"
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/licensing"
|
"github.com/grafana/grafana/pkg/services/licensing"
|
||||||
"github.com/grafana/grafana/pkg/services/login"
|
"github.com/grafana/grafana/pkg/services/login"
|
||||||
@ -392,6 +393,8 @@ func setupHTTPServerWithCfgDb(
|
|||||||
folderPermissionsService := accesscontrolmock.NewMockedPermissionsService()
|
folderPermissionsService := accesscontrolmock.NewMockedPermissionsService()
|
||||||
dashboardPermissionsService := accesscontrolmock.NewMockedPermissionsService()
|
dashboardPermissionsService := accesscontrolmock.NewMockedPermissionsService()
|
||||||
|
|
||||||
|
folderSvc := foldertest.NewFakeService()
|
||||||
|
|
||||||
// Create minimal HTTP Server
|
// Create minimal HTTP Server
|
||||||
hs := &HTTPServer{
|
hs := &HTTPServer{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
@ -408,6 +411,7 @@ func setupHTTPServerWithCfgDb(
|
|||||||
DashboardService: dashboardservice.ProvideDashboardService(
|
DashboardService: dashboardservice.ProvideDashboardService(
|
||||||
cfg, dashboardsStore, dashboardsStore, nil, features,
|
cfg, dashboardsStore, dashboardsStore, nil, features,
|
||||||
folderPermissionsService, dashboardPermissionsService, ac,
|
folderPermissionsService, dashboardPermissionsService, ac,
|
||||||
|
folderSvc,
|
||||||
),
|
),
|
||||||
preferenceService: preftest.NewPreferenceServiceFake(),
|
preferenceService: preftest.NewPreferenceServiceFake(),
|
||||||
userService: userSvc,
|
userService: userSvc,
|
||||||
|
@ -12,12 +12,15 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/api/dtos"
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
"github.com/grafana/grafana/pkg/api/routing"
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"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/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -37,12 +40,14 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
|
|||||||
folderPermissions := accesscontrolmock.NewMockedPermissionsService()
|
folderPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||||
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
|
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||||
|
|
||||||
|
folderSvc := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), settings, dashboardStore, dashboards.NewFakeFolderStore(t), mockSQLStore, featuremgmt.WithFeatures(), nil)
|
||||||
hs := &HTTPServer{
|
hs := &HTTPServer{
|
||||||
Cfg: settings,
|
Cfg: settings,
|
||||||
SQLStore: mockSQLStore,
|
SQLStore: mockSQLStore,
|
||||||
Features: features,
|
Features: features,
|
||||||
DashboardService: dashboardservice.ProvideDashboardService(
|
DashboardService: dashboardservice.ProvideDashboardService(
|
||||||
settings, dashboardStore, dashboards.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac,
|
settings, dashboardStore, dashboards.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac,
|
||||||
|
folderSvc,
|
||||||
),
|
),
|
||||||
AccessControl: accesscontrolmock.New().WithDisabled(),
|
AccessControl: accesscontrolmock.New().WithDisabled(),
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,11 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/api/dtos"
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
"github.com/grafana/grafana/pkg/api/routing"
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
@ -35,6 +37,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboardversion/dashvertest"
|
"github.com/grafana/grafana/pkg/services/dashboardversion/dashvertest"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/folder"
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
|
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||||
"github.com/grafana/grafana/pkg/services/guardian"
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/libraryelements"
|
"github.com/grafana/grafana/pkg/services/libraryelements"
|
||||||
@ -980,10 +983,13 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
|||||||
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
|
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||||
features := featuremgmt.WithFeatures()
|
features := featuremgmt.WithFeatures()
|
||||||
|
|
||||||
|
folderSvc := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), cfg, dashboardStore, folderStore, db.InitTestDB(t), featuremgmt.WithFeatures(), nil)
|
||||||
|
|
||||||
if dashboardService == nil {
|
if dashboardService == nil {
|
||||||
dashboardService = service.ProvideDashboardService(
|
dashboardService = service.ProvideDashboardService(
|
||||||
cfg, dashboardStore, folderStore, nil, features,
|
cfg, dashboardStore, folderStore, nil, features,
|
||||||
folderPermissions, dashboardPermissions, ac,
|
folderPermissions, dashboardPermissions, ac,
|
||||||
|
folderSvc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -997,6 +1003,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
|||||||
dashboardProvisioningService: service.ProvideDashboardService(
|
dashboardProvisioningService: service.ProvideDashboardService(
|
||||||
cfg, dashboardStore, folderStore, nil, features,
|
cfg, dashboardStore, folderStore, nil, features,
|
||||||
folderPermissions, dashboardPermissions, ac,
|
folderPermissions, dashboardPermissions, ac,
|
||||||
|
folderSvc,
|
||||||
),
|
),
|
||||||
DashboardService: dashboardService,
|
DashboardService: dashboardService,
|
||||||
Features: featuremgmt.WithFeatures(),
|
Features: featuremgmt.WithFeatures(),
|
||||||
|
@ -46,6 +46,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
|
|||||||
dashboardPermissionsService: dashboardPermissions,
|
dashboardPermissionsService: dashboardPermissions,
|
||||||
DashboardService: service.ProvideDashboardService(
|
DashboardService: service.ProvideDashboardService(
|
||||||
settings, dashboardStore, dashboards.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac,
|
settings, dashboardStore, dashboards.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac,
|
||||||
|
folderService,
|
||||||
),
|
),
|
||||||
AccessControl: accesscontrolmock.New().WithDisabled(),
|
AccessControl: accesscontrolmock.New().WithDisabled(),
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -38,7 +39,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewFolderNameScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope.
|
// 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 FolderStore) (string, ac.ScopeAttributeResolver) {
|
func NewFolderNameScopeResolver(db Store, folderDB FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||||
prefix := ScopeFoldersProvider.GetResourceScopeName("")
|
prefix := ScopeFoldersProvider.GetResourceScopeName("")
|
||||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||||
if !strings.HasPrefix(scope, prefix) {
|
if !strings.HasPrefix(scope, prefix) {
|
||||||
@ -52,12 +53,19 @@ func NewFolderNameScopeResolver(db Store, folderDB FolderStore) (string, ac.Scop
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return []string{ScopeFoldersProvider.GetResourceScopeUID(folder.UID)}, nil
|
|
||||||
|
result, err := getInheritedScopes(ctx, folder.OrgID, folder.UID, folderSvc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append([]string{ScopeFoldersProvider.GetResourceScopeUID(folder.UID)}, result...)
|
||||||
|
return result, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFolderIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:id:" into an uid based scope.
|
// 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 FolderStore) (string, ac.ScopeAttributeResolver) {
|
func NewFolderIDScopeResolver(db Store, folderDB FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||||
prefix := ScopeFoldersProvider.GetResourceScope("")
|
prefix := ScopeFoldersProvider.GetResourceScope("")
|
||||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||||
if !strings.HasPrefix(scope, prefix) {
|
if !strings.HasPrefix(scope, prefix) {
|
||||||
@ -78,13 +86,19 @@ func NewFolderIDScopeResolver(db Store, folderDB FolderStore) (string, ac.ScopeA
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{ScopeFoldersProvider.GetResourceScopeUID(folder.UID)}, nil
|
result, err := getInheritedScopes(ctx, folder.OrgID, folder.UID, folderSvc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append([]string{ScopeFoldersProvider.GetResourceScopeUID(folder.UID)}, result...)
|
||||||
|
return result, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDashboardIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:id:"
|
// NewDashboardIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:id:"
|
||||||
// into uid based scopes for both dashboard and folder
|
// into uid based scopes for both dashboard and folder
|
||||||
func NewDashboardIDScopeResolver(db Store, folderDB FolderStore) (string, ac.ScopeAttributeResolver) {
|
func NewDashboardIDScopeResolver(db Store, folderDB FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||||
prefix := ScopeDashboardsProvider.GetResourceScope("")
|
prefix := ScopeDashboardsProvider.GetResourceScope("")
|
||||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||||
if !strings.HasPrefix(scope, prefix) {
|
if !strings.HasPrefix(scope, prefix) {
|
||||||
@ -101,13 +115,13 @@ func NewDashboardIDScopeResolver(db Store, folderDB FolderStore) (string, ac.Sco
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveDashboardScope(ctx, db, folderDB, orgID, dashboard)
|
return resolveDashboardScope(ctx, db, folderDB, orgID, dashboard, folderSvc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDashboardUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:uid:"
|
// NewDashboardUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:uid:"
|
||||||
// into uid based scopes for both dashboard and folder
|
// into uid based scopes for both dashboard and folder
|
||||||
func NewDashboardUIDScopeResolver(db Store, folderDB FolderStore) (string, ac.ScopeAttributeResolver) {
|
func NewDashboardUIDScopeResolver(db Store, folderDB FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||||
prefix := ScopeDashboardsProvider.GetResourceScopeUID("")
|
prefix := ScopeDashboardsProvider.GetResourceScopeUID("")
|
||||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||||
if !strings.HasPrefix(scope, prefix) {
|
if !strings.HasPrefix(scope, prefix) {
|
||||||
@ -124,11 +138,11 @@ func NewDashboardUIDScopeResolver(db Store, folderDB FolderStore) (string, ac.Sc
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveDashboardScope(ctx, db, folderDB, orgID, dashboard)
|
return resolveDashboardScope(ctx, db, folderDB, orgID, dashboard, folderSvc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveDashboardScope(ctx context.Context, db Store, folderDB FolderStore, orgID int64, dashboard *Dashboard) ([]string, error) {
|
func resolveDashboardScope(ctx context.Context, db Store, folderDB FolderStore, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) {
|
||||||
var folderUID string
|
var folderUID string
|
||||||
if dashboard.FolderID < 0 {
|
if dashboard.FolderID < 0 {
|
||||||
return []string{ScopeDashboardsProvider.GetResourceScopeUID(dashboard.UID)}, nil
|
return []string{ScopeDashboardsProvider.GetResourceScopeUID(dashboard.UID)}, nil
|
||||||
@ -144,8 +158,36 @@ func resolveDashboardScope(ctx context.Context, db Store, folderDB FolderStore,
|
|||||||
folderUID = folder.UID
|
folderUID = folder.UID
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{
|
result, err := getInheritedScopes(ctx, orgID, folderUID, folderSvc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append([]string{
|
||||||
ScopeDashboardsProvider.GetResourceScopeUID(dashboard.UID),
|
ScopeDashboardsProvider.GetResourceScopeUID(dashboard.UID),
|
||||||
ScopeFoldersProvider.GetResourceScopeUID(folderUID),
|
ScopeFoldersProvider.GetResourceScopeUID(folderUID),
|
||||||
}, nil
|
},
|
||||||
|
result...,
|
||||||
|
)
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInheritedScopes(ctx context.Context, orgID int64, folderUID string, folderSvc folder.Service) ([]string, error) {
|
||||||
|
ancestors, err := folderSvc.GetParents(ctx, folder.GetParentsQuery{
|
||||||
|
UID: folderUID,
|
||||||
|
OrgID: orgID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// TODO return a specific error
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]string, 0, len(ancestors))
|
||||||
|
for _, ff := range ancestors {
|
||||||
|
result = append(result, ScopeFoldersProvider.GetResourceScopeUID(ff.UID))
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,19 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/folder"
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
|
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewFolderNameScopeResolver(t *testing.T) {
|
func TestNewFolderNameScopeResolver(t *testing.T) {
|
||||||
t.Run("prefix should be expected", func(t *testing.T) {
|
t.Run("prefix should be expected", func(t *testing.T) {
|
||||||
prefix, _ := NewFolderNameScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t))
|
prefix, _ := NewFolderNameScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
require.Equal(t, "folders:name:", prefix)
|
require.Equal(t, "folders:name:", prefix)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -33,7 +35,7 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
|
|||||||
|
|
||||||
scope := "folders:name:" + title
|
scope := "folders:name:" + title
|
||||||
|
|
||||||
_, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore)
|
_, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService())
|
||||||
|
|
||||||
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
|
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -43,16 +45,53 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
|
|||||||
|
|
||||||
folderStore.AssertCalled(t, "GetFolderByTitle", mock.Anything, orgId, title)
|
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 := NewFakeFolderStore(t)
|
||||||
|
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once()
|
||||||
|
|
||||||
|
scope := "folders:name:" + title
|
||||||
|
|
||||||
|
folderSvc := foldertest.NewFakeService()
|
||||||
|
folderSvc.ExpectedFolders = []*folder.Folder{
|
||||||
|
{
|
||||||
|
UID: "parent",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
UID: "grandparent",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, 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),
|
||||||
|
"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) {
|
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
||||||
dashboardStore := &FakeDashboardStore{}
|
dashboardStore := &FakeDashboardStore{}
|
||||||
_, resolver := NewFolderNameScopeResolver(dashboardStore, NewFakeFolderStore(t))
|
_, resolver := NewFolderNameScopeResolver(dashboardStore, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
|
|
||||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:123")
|
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:123")
|
||||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
||||||
})
|
})
|
||||||
t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) {
|
t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) {
|
||||||
dashboardStore := &FakeDashboardStore{}
|
dashboardStore := &FakeDashboardStore{}
|
||||||
_, resolver := NewFolderNameScopeResolver(dashboardStore, NewFakeFolderStore(t))
|
_, resolver := NewFolderNameScopeResolver(dashboardStore, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
|
|
||||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:name:")
|
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:name:")
|
||||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
||||||
@ -61,7 +100,7 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
|
|||||||
dashboardStore := &FakeDashboardStore{}
|
dashboardStore := &FakeDashboardStore{}
|
||||||
|
|
||||||
folderStore := NewFakeFolderStore(t)
|
folderStore := NewFakeFolderStore(t)
|
||||||
_, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore)
|
_, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService())
|
||||||
|
|
||||||
orgId := rand.Int63()
|
orgId := rand.Int63()
|
||||||
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
|
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
|
||||||
@ -76,7 +115,7 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
|
|||||||
|
|
||||||
func TestNewFolderIDScopeResolver(t *testing.T) {
|
func TestNewFolderIDScopeResolver(t *testing.T) {
|
||||||
t.Run("prefix should be expected", func(t *testing.T) {
|
t.Run("prefix should be expected", func(t *testing.T) {
|
||||||
prefix, _ := NewFolderIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t))
|
prefix, _ := NewFolderIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
require.Equal(t, "folders:id:", prefix)
|
require.Equal(t, "folders:id:", prefix)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -84,7 +123,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
|||||||
dashboardStore := &FakeDashboardStore{}
|
dashboardStore := &FakeDashboardStore{}
|
||||||
folderStore := NewFakeFolderStore(t)
|
folderStore := NewFakeFolderStore(t)
|
||||||
|
|
||||||
_, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore)
|
_, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService())
|
||||||
|
|
||||||
orgId := rand.Int63()
|
orgId := rand.Int63()
|
||||||
uid := util.GenerateShortUID()
|
uid := util.GenerateShortUID()
|
||||||
@ -101,9 +140,46 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
|||||||
|
|
||||||
folderStore.AssertCalled(t, "GetFolderByID", mock.Anything, orgId, db.ID)
|
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 := NewFakeFolderStore(t)
|
||||||
|
|
||||||
|
folderSvc := foldertest.NewFakeService()
|
||||||
|
folderSvc.ExpectedFolders = []*folder.Folder{
|
||||||
|
{
|
||||||
|
UID: "parent",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
UID: "grandparent",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, 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()
|
||||||
|
|
||||||
|
scope := "folders:id:" + strconv.FormatInt(db.ID, 10)
|
||||||
|
|
||||||
|
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),
|
||||||
|
"folders:uid:parent",
|
||||||
|
"folders:uid:grandparent",
|
||||||
|
}, 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) {
|
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
||||||
dashboardStore := &FakeDashboardStore{}
|
dashboardStore := &FakeDashboardStore{}
|
||||||
_, resolver := NewFolderIDScopeResolver(dashboardStore, NewFakeFolderStore(t))
|
_, resolver := NewFolderIDScopeResolver(dashboardStore, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
|
|
||||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:uid:123")
|
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:uid:123")
|
||||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
||||||
@ -114,7 +190,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
|||||||
dashboardStore = &FakeDashboardStore{}
|
dashboardStore = &FakeDashboardStore{}
|
||||||
orgId = rand.Int63()
|
orgId = rand.Int63()
|
||||||
scope = "folders:id:0"
|
scope = "folders:id:0"
|
||||||
_, resolver = NewFolderIDScopeResolver(dashboardStore, NewFakeFolderStore(t))
|
_, resolver = NewFolderIDScopeResolver(dashboardStore, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
)
|
)
|
||||||
|
|
||||||
resolved, err := resolver.Resolve(context.Background(), orgId, scope)
|
resolved, err := resolver.Resolve(context.Background(), orgId, scope)
|
||||||
@ -126,7 +202,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) {
|
t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) {
|
||||||
dashboardStore := &FakeDashboardStore{}
|
dashboardStore := &FakeDashboardStore{}
|
||||||
_, resolver := NewFolderIDScopeResolver(dashboardStore, NewFakeFolderStore(t))
|
_, resolver := NewFolderIDScopeResolver(dashboardStore, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
|
|
||||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:")
|
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:")
|
||||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
||||||
@ -135,7 +211,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
|||||||
dashboardStore := &FakeDashboardStore{}
|
dashboardStore := &FakeDashboardStore{}
|
||||||
folderStore := NewFakeFolderStore(t)
|
folderStore := NewFakeFolderStore(t)
|
||||||
|
|
||||||
_, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore)
|
_, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService())
|
||||||
|
|
||||||
orgId := rand.Int63()
|
orgId := rand.Int63()
|
||||||
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
|
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
|
||||||
@ -149,7 +225,7 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
|
|||||||
|
|
||||||
func TestNewDashboardIDScopeResolver(t *testing.T) {
|
func TestNewDashboardIDScopeResolver(t *testing.T) {
|
||||||
t.Run("prefix should be expected", func(t *testing.T) {
|
t.Run("prefix should be expected", func(t *testing.T) {
|
||||||
prefix, _ := NewDashboardIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t))
|
prefix, _ := NewDashboardIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
require.Equal(t, "dashboards:id:", prefix)
|
require.Equal(t, "dashboards:id:", prefix)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -157,7 +233,7 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
|
|||||||
store := &FakeDashboardStore{}
|
store := &FakeDashboardStore{}
|
||||||
folderStore := NewFakeFolderStore(t)
|
folderStore := NewFakeFolderStore(t)
|
||||||
|
|
||||||
_, resolver := NewDashboardIDScopeResolver(store, folderStore)
|
_, resolver := NewDashboardIDScopeResolver(store, folderStore, foldertest.NewFakeService())
|
||||||
|
|
||||||
orgID := rand.Int63()
|
orgID := rand.Int63()
|
||||||
folder := &folder.Folder{ID: 2, UID: "2"}
|
folder := &folder.Folder{ID: 2, UID: "2"}
|
||||||
@ -174,15 +250,52 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
|
|||||||
require.Equal(t, fmt.Sprintf("folders:uid:%s", folder.UID), resolvedScopes[1])
|
require.Equal(t, fmt.Sprintf("folders:uid:%s", folder.UID), resolvedScopes[1])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("resolver should inlude inherited scopes if any", func(t *testing.T) {
|
||||||
|
store := &FakeDashboardStore{}
|
||||||
|
folderStore := NewFakeFolderStore(t)
|
||||||
|
|
||||||
|
folderSvc := foldertest.NewFakeService()
|
||||||
|
folderSvc.ExpectedFolders = []*folder.Folder{
|
||||||
|
{
|
||||||
|
UID: "parent",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
UID: "grandparent",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, resolver := NewDashboardIDScopeResolver(store, folderStore, 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()
|
||||||
|
|
||||||
|
scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10))
|
||||||
|
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, resolvedScopes, 4)
|
||||||
|
|
||||||
|
if diff := cmp.Diff([]string{
|
||||||
|
fmt.Sprintf("dashboards:uid:%s", dashboard.UID),
|
||||||
|
fmt.Sprintf("folders:uid:%s", folder.UID),
|
||||||
|
"folders:uid:parent",
|
||||||
|
"folders:uid:grandparent",
|
||||||
|
}, resolvedScopes); diff != "" {
|
||||||
|
t.Errorf("Result mismatch (-want +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
||||||
_, resolver := NewDashboardIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t))
|
_, resolver := NewDashboardIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:uid:123")
|
_, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:uid:123")
|
||||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
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) {
|
t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) {
|
||||||
store := &FakeDashboardStore{}
|
store := &FakeDashboardStore{}
|
||||||
_, resolver := NewDashboardIDScopeResolver(store, NewFakeFolderStore(t))
|
_, resolver := NewDashboardIDScopeResolver(store, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
|
|
||||||
dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"}
|
dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"}
|
||||||
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
|
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||||
@ -197,14 +310,14 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
|
|||||||
|
|
||||||
func TestNewDashboardUIDScopeResolver(t *testing.T) {
|
func TestNewDashboardUIDScopeResolver(t *testing.T) {
|
||||||
t.Run("prefix should be expected", func(t *testing.T) {
|
t.Run("prefix should be expected", func(t *testing.T) {
|
||||||
prefix, _ := NewDashboardUIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t))
|
prefix, _ := NewDashboardUIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
require.Equal(t, "dashboards:uid:", prefix)
|
require.Equal(t, "dashboards:uid:", prefix)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) {
|
t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) {
|
||||||
store := &FakeDashboardStore{}
|
store := &FakeDashboardStore{}
|
||||||
folderStore := NewFakeFolderStore(t)
|
folderStore := NewFakeFolderStore(t)
|
||||||
_, resolver := NewDashboardUIDScopeResolver(store, folderStore)
|
_, resolver := NewDashboardUIDScopeResolver(store, folderStore, foldertest.NewFakeService())
|
||||||
|
|
||||||
orgID := rand.Int63()
|
orgID := rand.Int63()
|
||||||
folder := &folder.Folder{ID: 2, UID: "2"}
|
folder := &folder.Folder{ID: 2, UID: "2"}
|
||||||
@ -221,15 +334,53 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) {
|
|||||||
require.Equal(t, fmt.Sprintf("folders:uid:%s", folder.UID), resolvedScopes[1])
|
require.Equal(t, fmt.Sprintf("folders:uid:%s", folder.UID), resolvedScopes[1])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("resolver should include inherited scopes if any", func(t *testing.T) {
|
||||||
|
store := &FakeDashboardStore{}
|
||||||
|
folderStore := NewFakeFolderStore(t)
|
||||||
|
|
||||||
|
folderSvc := foldertest.NewFakeService()
|
||||||
|
folderSvc.ExpectedFolders = []*folder.Folder{
|
||||||
|
{
|
||||||
|
UID: "parent",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
UID: "grandparent",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resolver := NewDashboardUIDScopeResolver(store, folderStore, 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()
|
||||||
|
|
||||||
|
scope := ac.Scope("dashboards", "uid", dashboard.UID)
|
||||||
|
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, resolvedScopes, 4)
|
||||||
|
|
||||||
|
if diff := cmp.Diff([]string{
|
||||||
|
fmt.Sprintf("dashboards:uid:%s", dashboard.UID),
|
||||||
|
fmt.Sprintf("folders:uid:%s", folder.UID),
|
||||||
|
"folders:uid:parent",
|
||||||
|
"folders:uid:grandparent",
|
||||||
|
}, resolvedScopes); diff != "" {
|
||||||
|
t.Errorf("Result mismatch (-want +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
|
||||||
_, resolver := NewDashboardUIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t))
|
_, resolver := NewDashboardUIDScopeResolver(&FakeDashboardStore{}, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
_, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:id:123")
|
_, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:id:123")
|
||||||
require.ErrorIs(t, err, ac.ErrInvalidScope)
|
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) {
|
t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) {
|
||||||
store := &FakeDashboardStore{}
|
store := &FakeDashboardStore{}
|
||||||
_, resolver := NewDashboardUIDScopeResolver(store, NewFakeFolderStore(t))
|
_, resolver := NewDashboardUIDScopeResolver(store, NewFakeFolderStore(t), foldertest.NewFakeService())
|
||||||
|
|
||||||
dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"}
|
dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"}
|
||||||
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
|
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
|
||||||
|
@ -53,9 +53,10 @@ func ProvideDashboardService(
|
|||||||
cfg *setting.Cfg, dashboardStore dashboards.Store, folderStore dashboards.FolderStore, dashAlertExtractor alerting.DashAlertExtractor,
|
cfg *setting.Cfg, dashboardStore dashboards.Store, folderStore dashboards.FolderStore, dashAlertExtractor alerting.DashAlertExtractor,
|
||||||
features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
|
features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||||
dashboardPermissionsService accesscontrol.DashboardPermissionsService, ac accesscontrol.AccessControl,
|
dashboardPermissionsService accesscontrol.DashboardPermissionsService, ac accesscontrol.AccessControl,
|
||||||
|
folderSvc folder.Service,
|
||||||
) *DashboardServiceImpl {
|
) *DashboardServiceImpl {
|
||||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(dashboardStore, folderStore))
|
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(dashboardStore, folderStore, folderSvc))
|
||||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashboardStore, folderStore))
|
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashboardStore, folderStore, folderSvc))
|
||||||
|
|
||||||
return &DashboardServiceImpl{
|
return &DashboardServiceImpl{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
"github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
|
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||||
"github.com/grafana/grafana/pkg/services/guardian"
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||||
@ -831,6 +832,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
|
|||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.New(),
|
accesscontrolmock.New(),
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
guardian.InitLegacyGuardian(sqlStore, service, &teamtest.FakeService{})
|
guardian.InitLegacyGuardian(sqlStore, service, &teamtest.FakeService{})
|
||||||
|
|
||||||
@ -890,6 +892,7 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt
|
|||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.New(),
|
accesscontrolmock.New(),
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -911,6 +914,7 @@ func callSaveWithError(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSto
|
|||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.New(),
|
accesscontrolmock.New(),
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
_, err = service.SaveDashboard(context.Background(), &dto, false)
|
_, err = service.SaveDashboard(context.Background(), &dto, false)
|
||||||
return err
|
return err
|
||||||
@ -950,6 +954,7 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto
|
|||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.New(),
|
accesscontrolmock.New(),
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -990,6 +995,7 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da
|
|||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.New(),
|
accesscontrolmock.New(),
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
res, err := service.SaveDashboard(context.Background(), &dto, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -51,8 +51,6 @@ func ProvideService(
|
|||||||
features featuremgmt.FeatureToggles,
|
features featuremgmt.FeatureToggles,
|
||||||
folderPermissionsService accesscontrol.FolderPermissionsService,
|
folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||||
) folder.Service {
|
) folder.Service {
|
||||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore, folderStore))
|
|
||||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore, folderStore))
|
|
||||||
store := ProvideStore(db, cfg, features)
|
store := ProvideStore(db, cfg, features)
|
||||||
svr := &Service{
|
svr := &Service{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
@ -68,6 +66,9 @@ func ProvideService(
|
|||||||
if features.IsEnabled(featuremgmt.FlagNestedFolders) {
|
if features.IsEnabled(featuremgmt.FlagNestedFolders) {
|
||||||
svr.DBMigration(db)
|
svr.DBMigration(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore, folderStore, svr))
|
||||||
|
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore, folderStore, svr))
|
||||||
return svr
|
return svr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,6 +186,13 @@ func (s *Service) GetChildren(ctx context.Context, cmd *folder.GetChildrenQuery)
|
|||||||
return filtered, nil
|
return filtered, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetParents(ctx context.Context, q folder.GetParentsQuery) ([]*folder.Folder, error) {
|
||||||
|
if !s.features.IsEnabled(featuremgmt.FlagNestedFolders) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return s.store.GetParents(ctx, q)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) getFolderByID(ctx context.Context, user *user.SignedInUser, id int64, orgID int64) (*folder.Folder, error) {
|
func (s *Service) getFolderByID(ctx context.Context, user *user.SignedInUser, id int64, orgID int64) (*folder.Folder, error) {
|
||||||
if id == 0 {
|
if id == 0 {
|
||||||
return &folder.Folder{ID: id, Title: "General"}, nil
|
return &folder.Folder{ID: id, Title: "General"}, nil
|
||||||
|
@ -21,6 +21,11 @@ var _ folder.Service = (*FakeService)(nil)
|
|||||||
func (s *FakeService) GetChildren(ctx context.Context, cmd *folder.GetChildrenQuery) ([]*folder.Folder, error) {
|
func (s *FakeService) GetChildren(ctx context.Context, cmd *folder.GetChildrenQuery) ([]*folder.Folder, error) {
|
||||||
return s.ExpectedFolders, s.ExpectedError
|
return s.ExpectedFolders, s.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FakeService) GetParents(ctx context.Context, q folder.GetParentsQuery) ([]*folder.Folder, error) {
|
||||||
|
return s.ExpectedFolders, s.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FakeService) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (*folder.Folder, error) {
|
func (s *FakeService) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (*folder.Folder, error) {
|
||||||
return s.ExpectedFolder, s.ExpectedError
|
return s.ExpectedFolder, s.ExpectedError
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ import (
|
|||||||
type Service interface {
|
type Service interface {
|
||||||
// GetChildren returns an array containing all child folders.
|
// GetChildren returns an array containing all child folders.
|
||||||
GetChildren(ctx context.Context, cmd *GetChildrenQuery) ([]*Folder, error)
|
GetChildren(ctx context.Context, cmd *GetChildrenQuery) ([]*Folder, error)
|
||||||
|
// GetParents returns an array containing add parent folders if nested folders are enabled
|
||||||
|
// otherwise it returns an empty array
|
||||||
|
GetParents(ctx context.Context, q GetParentsQuery) ([]*Folder, error)
|
||||||
Create(ctx context.Context, cmd *CreateFolderCommand) (*Folder, error)
|
Create(ctx context.Context, cmd *CreateFolderCommand) (*Folder, error)
|
||||||
|
|
||||||
// GetFolder takes a GetFolderCommand and returns a folder matching the
|
// GetFolder takes a GetFolderCommand and returns a folder matching the
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
dashdb "github.com/grafana/grafana/pkg/services/dashboards/database"
|
dashdb "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
|
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||||
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
@ -601,7 +602,7 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ac := accesscontrolmock.New().WithPermissions(permissions)
|
ac := accesscontrolmock.New().WithPermissions(permissions)
|
||||||
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashStore, dashStore))
|
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashStore, dashStore, foldertest.NewFakeService()))
|
||||||
license := licensingtest.NewFakeLicensing()
|
license := licensingtest.NewFakeLicensing()
|
||||||
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
|
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
|
||||||
teamSvc := teamimpl.ProvideService(store, store.Cfg)
|
teamSvc := teamimpl.ProvideService(store, store.Cfg)
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/folder"
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
"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/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||||
@ -293,6 +294,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
|
|||||||
service := dashboardservice.ProvideDashboardService(
|
service := dashboardservice.ProvideDashboardService(
|
||||||
cfg, dashboardStore, dashboardStore, dashAlertExtractor,
|
cfg, dashboardStore, dashboardStore, dashAlertExtractor,
|
||||||
features, folderPermissions, dashboardPermissions, ac,
|
features, folderPermissions, dashboardPermissions, ac,
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
dashboard, err := service.SaveDashboard(context.Background(), dashItem, true)
|
dashboard, err := service.SaveDashboard(context.Background(), dashItem, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -437,6 +439,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
|||||||
dashboardService := dashboardservice.ProvideDashboardService(
|
dashboardService := dashboardservice.ProvideDashboardService(
|
||||||
sqlStore.Cfg, dashboardStore, dashboardStore, nil,
|
sqlStore.Cfg, dashboardStore, dashboardStore, nil,
|
||||||
features, folderPermissions, dashboardPermissions, ac,
|
features, folderPermissions, dashboardPermissions, ac,
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
guardian.InitLegacyGuardian(sqlStore, dashboardService, &teamtest.FakeService{})
|
guardian.InitLegacyGuardian(sqlStore, dashboardService, &teamtest.FakeService{})
|
||||||
service := LibraryElementService{
|
service := LibraryElementService{
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/folder"
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
"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/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/libraryelements"
|
"github.com/grafana/grafana/pkg/services/libraryelements"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
@ -706,6 +707,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash
|
|||||||
service := dashboardservice.ProvideDashboardService(
|
service := dashboardservice.ProvideDashboardService(
|
||||||
cfg, dashboardStore, dashboardStore, dashAlertService,
|
cfg, dashboardStore, dashboardStore, dashAlertService,
|
||||||
featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), acmock.NewMockedPermissionsService(), ac,
|
featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), acmock.NewMockedPermissionsService(), ac,
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
dashboard, err := service.SaveDashboard(context.Background(), dashItem, true)
|
dashboard, err := service.SaveDashboard(context.Background(), dashItem, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/folder"
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
"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/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert"
|
"github.com/grafana/grafana/pkg/services/ngalert"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||||
@ -81,6 +82,7 @@ func SetupTestEnv(tb testing.TB, baseInterval time.Duration) (*ngalert.AlertNG,
|
|||||||
dashboardService := dashboardservice.ProvideDashboardService(
|
dashboardService := dashboardservice.ProvideDashboardService(
|
||||||
cfg, dashboardStore, dashboardStore, nil,
|
cfg, dashboardStore, dashboardStore, nil,
|
||||||
features, folderPermissions, dashboardPermissions, ac,
|
features, folderPermissions, dashboardPermissions, ac,
|
||||||
|
foldertest.NewFakeService(),
|
||||||
)
|
)
|
||||||
|
|
||||||
tracer := tracing.InitializeTracerForTest()
|
tracer := tracing.InitializeTracerForTest()
|
||||||
|
Loading…
Reference in New Issue
Block a user