Folders: Set folder creation permission as part of legacy create (#94040)
* Add folder store to dashboard permissions * Include folder store in annotation scope resolver * Add folder store when initialising library elements * Include folder store in search v2 service initialisation * Include folder store in GetInheritedScopes * Add folder store to folder permissions provider * Include cfg, folder permissions in folder service * Move setting of folder permissions for folder service create method
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/authlib/claims"
|
||||
"github.com/grafana/dskit/concurrency"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@@ -29,11 +30,13 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/services/store/entity"
|
||||
"github.com/grafana/grafana/pkg/services/supportbundles"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
@@ -46,6 +49,8 @@ type Service struct {
|
||||
dashboardStore dashboards.Store
|
||||
dashboardFolderStore folder.FolderStore
|
||||
features featuremgmt.FeatureToggles
|
||||
cfg *setting.Cfg
|
||||
folderPermissions accesscontrol.FolderPermissionsService
|
||||
accessControl accesscontrol.AccessControl
|
||||
// bus is currently used to publish event in case of folder full path change.
|
||||
// For example when a folder is moved to another folder or when a folder is renamed.
|
||||
@@ -65,6 +70,8 @@ func ProvideService(
|
||||
folderStore folder.FolderStore,
|
||||
db db.DB, // DB for the (new) nested folder store
|
||||
features featuremgmt.FeatureToggles,
|
||||
cfg *setting.Cfg,
|
||||
folderPermissions accesscontrol.FolderPermissionsService,
|
||||
supportBundles supportbundles.Service,
|
||||
r prometheus.Registerer,
|
||||
tracer tracing.Tracer,
|
||||
@@ -75,6 +82,8 @@ func ProvideService(
|
||||
dashboardFolderStore: folderStore,
|
||||
store: store,
|
||||
features: features,
|
||||
cfg: cfg,
|
||||
folderPermissions: folderPermissions,
|
||||
accessControl: ac,
|
||||
bus: bus,
|
||||
db: db,
|
||||
@@ -86,9 +95,9 @@ func ProvideService(
|
||||
|
||||
supportBundles.RegisterSupportItemCollector(srv.supportBundleCollector())
|
||||
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(folderStore, srv))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(folderStore, srv))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(srv))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(folderStore, store))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(folderStore, store))
|
||||
ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(store))
|
||||
return srv
|
||||
}
|
||||
|
||||
@@ -658,9 +667,43 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (
|
||||
if nestedFolder != nil && nestedFolder.ParentUID != "" {
|
||||
f.ParentUID = nestedFolder.ParentUID
|
||||
}
|
||||
if err = s.setDefaultFolderPermissions(ctx, cmd.OrgID, user, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (s *Service) setDefaultFolderPermissions(ctx context.Context, orgID int64, user identity.Requester, folder *folder.Folder) error {
|
||||
if !s.cfg.RBAC.PermissionsOnCreation("folder") {
|
||||
return nil
|
||||
}
|
||||
|
||||
var permissions []accesscontrol.SetResourcePermissionCommand
|
||||
|
||||
if user.IsIdentityType(claims.TypeUser) {
|
||||
userID, err := user.GetInternalID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{
|
||||
UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(),
|
||||
})
|
||||
}
|
||||
|
||||
isNested := folder.ParentUID != ""
|
||||
if !isNested || !s.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) {
|
||||
permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{
|
||||
{BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()},
|
||||
{BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()},
|
||||
}...)
|
||||
}
|
||||
|
||||
_, err := s.folderPermissions.SetPermissions(ctx, orgID, folder.UID, permissions...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) (*folder.Folder, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "folder.Update")
|
||||
defer span.End()
|
||||
|
||||
@@ -62,10 +62,11 @@ func TestIntegrationProvideFolderService(t *testing.T) {
|
||||
}
|
||||
t.Run("should register scope resolvers", func(t *testing.T) {
|
||||
ac := acmock.New()
|
||||
db, _ := db.InitTestDBWithCfg(t)
|
||||
db, cfg := db.InitTestDBWithCfg(t)
|
||||
folderPermissions := acmock.NewMockedPermissionsService()
|
||||
store := ProvideStore(db)
|
||||
ProvideService(store, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), nil, nil, db,
|
||||
featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest())
|
||||
featuremgmt.WithFeatures(), cfg, folderPermissions, supportbundlestest.NewFakeBundleService(), nil, tracing.InitializeTracerForTest())
|
||||
|
||||
require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 3)
|
||||
})
|
||||
@@ -97,6 +98,7 @@ func TestIntegrationFolderService(t *testing.T) {
|
||||
dashboardFolderStore: folderStore,
|
||||
store: nestedFolderStore,
|
||||
features: features,
|
||||
cfg: cfg,
|
||||
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
|
||||
db: db,
|
||||
accessControl: acimpl.ProvideAccessControl(features, zanzana.NewNoopClient()),
|
||||
@@ -439,6 +441,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
dashboardFolderStore: folderStore,
|
||||
store: nestedFolderStore,
|
||||
features: featuresFlagOn,
|
||||
cfg: cfg,
|
||||
bus: b,
|
||||
db: db,
|
||||
accessControl: ac,
|
||||
@@ -494,7 +497,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOn, db, serviceWithFlagOn, dashSrv, ac)
|
||||
require.NoError(t, err)
|
||||
|
||||
elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOn, featuresFlagOn, ac)
|
||||
elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOn, serviceWithFlagOn.store, featuresFlagOn, ac)
|
||||
lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, serviceWithFlagOn)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -554,6 +557,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
dashboardFolderStore: folderStore,
|
||||
store: nestedFolderStore,
|
||||
features: featuresFlagOff,
|
||||
cfg: cfg,
|
||||
bus: b,
|
||||
db: db,
|
||||
registry: make(map[string]folder.RegistryService),
|
||||
@@ -576,7 +580,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOff, db, serviceWithFlagOff, dashSrv, ac)
|
||||
require.NoError(t, err)
|
||||
|
||||
elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOff, featuresFlagOff, ac)
|
||||
elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOff, serviceWithFlagOff.store, featuresFlagOff, ac)
|
||||
lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, serviceWithFlagOff)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -632,6 +636,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
|
||||
dashboardFolderStore: folderStore,
|
||||
features: featuresFlagOff,
|
||||
cfg: cfg,
|
||||
bus: b,
|
||||
db: db,
|
||||
registry: make(map[string]folder.RegistryService),
|
||||
@@ -705,7 +710,7 @@ func TestIntegrationNestedFolderService(t *testing.T) {
|
||||
CanEditValue: true,
|
||||
})
|
||||
|
||||
elementService := libraryelements.ProvideService(cfg, db, routeRegister, tc.service, tc.featuresFlag, ac)
|
||||
elementService := libraryelements.ProvideService(cfg, db, routeRegister, tc.service, tc.service.store, tc.featuresFlag, ac)
|
||||
lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, tc.service)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -810,6 +815,7 @@ func TestNestedFolderServiceFeatureToggle(t *testing.T) {
|
||||
dashboardStore: &dashStore,
|
||||
dashboardFolderStore: dashboardFolderStore,
|
||||
features: featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders),
|
||||
cfg: setting.NewCfg(),
|
||||
accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()),
|
||||
metrics: newFoldersMetrics(nil),
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
@@ -847,6 +853,7 @@ func TestFolderServiceDualWrite(t *testing.T) {
|
||||
dashboardStore: dashStore,
|
||||
dashboardFolderStore: dashboardFolderStore,
|
||||
features: featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders),
|
||||
cfg: cfg,
|
||||
accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()),
|
||||
metrics: newFoldersMetrics(nil),
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
@@ -1479,6 +1486,7 @@ func TestIntegrationNestedFolderSharedWithMe(t *testing.T) {
|
||||
dashboardFolderStore: folderStore,
|
||||
store: nestedFolderStore,
|
||||
features: featuresFlagOn,
|
||||
cfg: cfg,
|
||||
bus: b,
|
||||
db: db,
|
||||
accessControl: ac,
|
||||
@@ -1901,6 +1909,7 @@ func TestFolderServiceGetFolder(t *testing.T) {
|
||||
dashboardFolderStore: folderStore,
|
||||
store: nestedFolderStore,
|
||||
features: features,
|
||||
cfg: cfg,
|
||||
bus: b,
|
||||
db: db,
|
||||
accessControl: ac,
|
||||
@@ -1983,6 +1992,7 @@ func TestFolderServiceGetFolders(t *testing.T) {
|
||||
dashboardFolderStore: folderStore,
|
||||
store: nestedFolderStore,
|
||||
features: featuresFlagOff,
|
||||
cfg: cfg,
|
||||
bus: b,
|
||||
db: db,
|
||||
accessControl: ac,
|
||||
@@ -2070,6 +2080,7 @@ func TestGetChildrenFilterByPermission(t *testing.T) {
|
||||
dashboardFolderStore: folderStore,
|
||||
store: nestedFolderStore,
|
||||
features: features,
|
||||
cfg: cfg,
|
||||
bus: b,
|
||||
db: db,
|
||||
accessControl: ac,
|
||||
@@ -2533,6 +2544,7 @@ func setup(t *testing.T, dashStore dashboards.Store, dashboardFolderStore folder
|
||||
dashboardFolderStore: dashboardFolderStore,
|
||||
store: nestedFolderStore,
|
||||
features: features,
|
||||
cfg: setting.NewCfg(),
|
||||
accessControl: ac,
|
||||
db: db,
|
||||
metrics: newFoldersMetrics(nil),
|
||||
|
||||
Reference in New Issue
Block a user