mirror of https://github.com/grafana/grafana.git
				
				
				
			RBAC: Add scope resolvers for dashboards (#50110)
* Inject access control into dashboard service * Add function to parse id scopes * Add dashboard as return value * Update mock * Return only err to keep service interface * Add scope resolvers for dashboard id scopes * Add function to parse uid scopes * Add dashboard uid scope resolver * Register scope resolvers for dashboards Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									9f6afb3475
								
							
						
					
					
						commit
						c4a75f9eb3
					
				| 
						 | 
				
			
			@ -362,11 +362,28 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo
 | 
			
		|||
		db.Cfg.RBACEnabled = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var acmock *accesscontrolmock.Mock
 | 
			
		||||
 | 
			
		||||
	license := &licensing.OSSLicensingService{}
 | 
			
		||||
	routeRegister := routing.NewRouteRegister()
 | 
			
		||||
	dashboardsStore := dashboardsstore.ProvideDashboardStore(db)
 | 
			
		||||
 | 
			
		||||
	routeRegister := routing.NewRouteRegister()
 | 
			
		||||
	var acmock *accesscontrolmock.Mock
 | 
			
		||||
	var ac accesscontrol.AccessControl
 | 
			
		||||
 | 
			
		||||
	// Defining the accesscontrol service has to be done before registering routes
 | 
			
		||||
	if useFakeAccessControl {
 | 
			
		||||
		acmock = accesscontrolmock.New()
 | 
			
		||||
		if !enableAccessControl {
 | 
			
		||||
			acmock = acmock.WithDisabled()
 | 
			
		||||
		}
 | 
			
		||||
		ac = acmock
 | 
			
		||||
	} else {
 | 
			
		||||
		var err error
 | 
			
		||||
		ac, err = ossaccesscontrol.ProvideService(features, cfg, database.ProvideService(db), routeRegister)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, ac, database.ProvideService(db), license)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	// Create minimal HTTP Server
 | 
			
		||||
	hs := &HTTPServer{
 | 
			
		||||
| 
						 | 
				
			
			@ -377,37 +394,18 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo
 | 
			
		|||
		RouteRegister:          routeRegister,
 | 
			
		||||
		SQLStore:               store,
 | 
			
		||||
		License:                &licensing.OSSLicensingService{},
 | 
			
		||||
		AccessControl:          ac,
 | 
			
		||||
		teamPermissionsService: teamPermissionService,
 | 
			
		||||
		searchUsersService:     searchusers.ProvideUsersService(db, filters.ProvideOSSSearchUserFilter()),
 | 
			
		||||
		dashboardService: dashboardservice.ProvideDashboardService(
 | 
			
		||||
			cfg, dashboardsStore, nil, features,
 | 
			
		||||
			accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
			accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), ac,
 | 
			
		||||
		),
 | 
			
		||||
		preferenceService: preftest.NewPreferenceServiceFake(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Defining the accesscontrol service has to be done before registering routes
 | 
			
		||||
	if useFakeAccessControl {
 | 
			
		||||
		acmock = accesscontrolmock.New()
 | 
			
		||||
		if !enableAccessControl {
 | 
			
		||||
			acmock = acmock.WithDisabled()
 | 
			
		||||
		}
 | 
			
		||||
		hs.AccessControl = acmock
 | 
			
		||||
		teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, acmock, database.ProvideService(db), hs.License)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
		hs.teamPermissionsService = teamPermissionService
 | 
			
		||||
	} else {
 | 
			
		||||
		ac, errInitAc := ossaccesscontrol.ProvideService(hs.Features, hs.Cfg, database.ProvideService(db), routing.NewRouteRegister())
 | 
			
		||||
		require.NoError(t, errInitAc)
 | 
			
		||||
		hs.AccessControl = ac
 | 
			
		||||
		// Perform role registration
 | 
			
		||||
		err := hs.declareFixedRoles()
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
		err = ac.RegisterFixedRoles(context.Background())
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
		teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, ac, database.ProvideService(db), hs.License)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
		hs.teamPermissionsService = teamPermissionService
 | 
			
		||||
	}
 | 
			
		||||
	require.NoError(t, hs.declareFixedRoles())
 | 
			
		||||
	require.NoError(t, hs.AccessControl.(accesscontrol.RoleRegistry).RegisterFixedRoles(context.Background()))
 | 
			
		||||
 | 
			
		||||
	// Instantiate a new Server
 | 
			
		||||
	m := web.New()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,11 +26,12 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
 | 
			
		|||
	t.Run("Dashboard permissions test", func(t *testing.T) {
 | 
			
		||||
		settings := setting.NewCfg()
 | 
			
		||||
		dashboardStore := &dashboards.FakeDashboardStore{}
 | 
			
		||||
		dashboardStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Return(nil)
 | 
			
		||||
		dashboardStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Return(nil, nil)
 | 
			
		||||
		defer dashboardStore.AssertExpectations(t)
 | 
			
		||||
 | 
			
		||||
		features := featuremgmt.WithFeatures()
 | 
			
		||||
		mockSQLStore := mockstore.NewSQLStoreMock()
 | 
			
		||||
		ac := accesscontrolmock.New()
 | 
			
		||||
		folderPermissions := accesscontrolmock.NewMockedPermissionsService()
 | 
			
		||||
		dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +40,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
 | 
			
		|||
			SQLStore: mockSQLStore,
 | 
			
		||||
			Features: features,
 | 
			
		||||
			dashboardService: dashboardservice.ProvideDashboardService(
 | 
			
		||||
				settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions,
 | 
			
		||||
				settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
			),
 | 
			
		||||
			AccessControl: accesscontrolmock.New().WithDisabled(),
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -953,10 +953,16 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
 | 
			
		|||
	libraryPanelsService := mockLibraryPanelService{}
 | 
			
		||||
	libraryElementsService := mockLibraryElementService{}
 | 
			
		||||
	cfg := setting.NewCfg()
 | 
			
		||||
	ac := accesscontrolmock.New()
 | 
			
		||||
	folderPermissions := accesscontrolmock.NewMockedPermissionsService()
 | 
			
		||||
	dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
 | 
			
		||||
	features := featuremgmt.WithFeatures()
 | 
			
		||||
 | 
			
		||||
	if dashboardService == nil {
 | 
			
		||||
		dashboardService = service.ProvideDashboardService(cfg, dashboardStore, nil, features, nil, accesscontrolmock.NewMockedPermissionsService())
 | 
			
		||||
		dashboardService = service.ProvideDashboardService(
 | 
			
		||||
			cfg, dashboardStore, nil, features,
 | 
			
		||||
			folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hs := &HTTPServer{
 | 
			
		||||
| 
						 | 
				
			
			@ -969,7 +975,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
 | 
			
		|||
		AccessControl:         accesscontrolmock.New(),
 | 
			
		||||
		dashboardProvisioningService: service.ProvideDashboardService(
 | 
			
		||||
			cfg, dashboardStore, nil, features,
 | 
			
		||||
			accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
			folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
		),
 | 
			
		||||
		dashboardService: dashboardService,
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
 | 
			
		|||
	defer dashboardStore.AssertExpectations(t)
 | 
			
		||||
 | 
			
		||||
	features := featuremgmt.WithFeatures()
 | 
			
		||||
	ac := accesscontrolmock.New()
 | 
			
		||||
	folderPermissions := accesscontrolmock.NewMockedPermissionsService()
 | 
			
		||||
	dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +43,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
 | 
			
		|||
		folderPermissionsService:    folderPermissions,
 | 
			
		||||
		dashboardPermissionsService: dashboardPermissions,
 | 
			
		||||
		dashboardService: service.ProvideDashboardService(
 | 
			
		||||
			settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions,
 | 
			
		||||
			settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
		),
 | 
			
		||||
		AccessControl: accesscontrolmock.New().WithDisabled(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,7 +113,7 @@ func ProvideDashboardPermissions(
 | 
			
		|||
) (*DashboardPermissionsService, error) {
 | 
			
		||||
	getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*models.Dashboard, error) {
 | 
			
		||||
		query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
 | 
			
		||||
		if err := dashboardStore.GetDashboard(ctx, query); err != nil {
 | 
			
		||||
		if _, err := dashboardStore.GetDashboard(ctx, query); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return query.Result, nil
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +142,7 @@ func ProvideDashboardPermissions(
 | 
			
		|||
			}
 | 
			
		||||
			if dashboard.FolderId > 0 {
 | 
			
		||||
				query := &models.GetDashboardQuery{Id: dashboard.FolderId, OrgId: orgID}
 | 
			
		||||
				if err := dashboardStore.GetDashboard(ctx, query); err != nil {
 | 
			
		||||
				if _, err := dashboardStore.GetDashboard(ctx, query); err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				return []string{dashboards.ScopeFoldersProvider.GetResourceScopeUID(query.Result.Uid)}, nil
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +196,7 @@ func ProvideFolderPermissions(
 | 
			
		|||
		ResourceAttribute: "uid",
 | 
			
		||||
		ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
 | 
			
		||||
			query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
 | 
			
		||||
			if err := dashboardStore.GetDashboard(ctx, query); err != nil {
 | 
			
		||||
			if _, err := dashboardStore.GetDashboard(ctx, query); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package accesscontrol
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +10,26 @@ const (
 | 
			
		|||
	maxPrefixParts = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func ParseScopeID(scope string) (int64, error) {
 | 
			
		||||
	id, err := strconv.ParseInt(ScopeSuffix(scope), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, ErrInvalidScope
 | 
			
		||||
	}
 | 
			
		||||
	return id, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ParseScopeUID(scope string) (string, error) {
 | 
			
		||||
	uid := ScopeSuffix(scope)
 | 
			
		||||
	if len(uid) == 0 {
 | 
			
		||||
		return "", ErrInvalidScope
 | 
			
		||||
	}
 | 
			
		||||
	return uid, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ScopeSuffix(scope string) string {
 | 
			
		||||
	return scope[len(ScopePrefix(scope)):]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetResourceScope(resource string, resourceID string) string {
 | 
			
		||||
	return Scope(resource, "id", resourceID)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,9 @@ package dashboards
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/grafana/grafana/pkg/models"
 | 
			
		||||
	ac "github.com/grafana/grafana/pkg/services/accesscontrol"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,9 +64,9 @@ func NewFolderIDScopeResolver(db Store) (string, ac.ScopeAttributeResolver) {
 | 
			
		|||
			return nil, ac.ErrInvalidScope
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		id, err := strconv.ParseInt(scope[len(prefix):], 10, 64)
 | 
			
		||||
		id, err := ac.ParseScopeID(scope)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, ac.ErrInvalidScope
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if id == 0 {
 | 
			
		||||
| 
						 | 
				
			
			@ -81,3 +81,66 @@ func NewFolderIDScopeResolver(db Store) (string, ac.ScopeAttributeResolver) {
 | 
			
		|||
		return []string{ScopeFoldersProvider.GetResourceScopeUID(folder.Uid)}, nil
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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) (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) {
 | 
			
		||||
			return nil, ac.ErrInvalidScope
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		id, err := ac.ParseScopeID(scope)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dashboard, err := db.GetDashboard(ctx, &models.GetDashboardQuery{Id: id, OrgId: orgID})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return resolveDashboardScope(ctx, db, orgID, dashboard)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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) (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) {
 | 
			
		||||
			return nil, ac.ErrInvalidScope
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		uid, err := ac.ParseScopeUID(scope)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dashboard, err := db.GetDashboard(ctx, &models.GetDashboardQuery{Uid: uid, OrgId: orgID})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return resolveDashboardScope(ctx, db, orgID, dashboard)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func resolveDashboardScope(ctx context.Context, db Store, orgID int64, dashboard *models.Dashboard) ([]string, error) {
 | 
			
		||||
	var folderUID string
 | 
			
		||||
	if dashboard.FolderId == 0 {
 | 
			
		||||
		folderUID = ac.GeneralFolderUID
 | 
			
		||||
	} else {
 | 
			
		||||
		folder, err := db.GetFolderByID(ctx, orgID, dashboard.FolderId)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		folderUID = folder.Uid
 | 
			
		||||
	}
 | 
			
		||||
	return []string{
 | 
			
		||||
		ScopeDashboardsProvider.GetResourceScopeUID(dashboard.Uid),
 | 
			
		||||
		ScopeFoldersProvider.GetResourceScopeUID(folderUID),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -144,3 +144,96 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
 | 
			
		|||
		require.Nil(t, resolvedScopes)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewDashboardIDScopeResolver(t *testing.T) {
 | 
			
		||||
	t.Run("prefix should be expected", func(t *testing.T) {
 | 
			
		||||
		prefix, _ := NewDashboardIDScopeResolver(&FakeDashboardStore{})
 | 
			
		||||
		require.Equal(t, "dashboards:id:", prefix)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) {
 | 
			
		||||
		store := &FakeDashboardStore{}
 | 
			
		||||
 | 
			
		||||
		_, resolver := NewDashboardIDScopeResolver(store)
 | 
			
		||||
 | 
			
		||||
		orgID := rand.Int63()
 | 
			
		||||
		folder := &models.Folder{Id: 2, Uid: "2"}
 | 
			
		||||
		dashboard := &models.Dashboard{Id: 1, FolderId: folder.Id, Uid: "1"}
 | 
			
		||||
 | 
			
		||||
		store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
 | 
			
		||||
		store.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, 2)
 | 
			
		||||
		require.Equal(t, fmt.Sprintf("dashboards:uid:%s", dashboard.Uid), resolvedScopes[0])
 | 
			
		||||
		require.Equal(t, fmt.Sprintf("folders:uid:%s", folder.Uid), resolvedScopes[1])
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
 | 
			
		||||
		_, resolver := NewDashboardIDScopeResolver(&FakeDashboardStore{})
 | 
			
		||||
		_, 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)
 | 
			
		||||
 | 
			
		||||
		dashboard := &models.Dashboard{Id: 1, FolderId: 0, Uid: "1"}
 | 
			
		||||
		store.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)
 | 
			
		||||
 | 
			
		||||
		require.Len(t, resolved, 2)
 | 
			
		||||
		require.Equal(t, "dashboards:uid:1", resolved[0])
 | 
			
		||||
		require.Equal(t, "folders:uid:general", resolved[1])
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewDashboardUIDScopeResolver(t *testing.T) {
 | 
			
		||||
	t.Run("prefix should be expected", func(t *testing.T) {
 | 
			
		||||
		prefix, _ := NewDashboardUIDScopeResolver(&FakeDashboardStore{})
 | 
			
		||||
		require.Equal(t, "dashboards:uid:", prefix)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) {
 | 
			
		||||
		store := &FakeDashboardStore{}
 | 
			
		||||
		_, resolver := NewDashboardUIDScopeResolver(store)
 | 
			
		||||
 | 
			
		||||
		orgID := rand.Int63()
 | 
			
		||||
		folder := &models.Folder{Id: 2, Uid: "2"}
 | 
			
		||||
		dashboard := &models.Dashboard{Id: 1, FolderId: folder.Id, Uid: "1"}
 | 
			
		||||
 | 
			
		||||
		store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
 | 
			
		||||
		store.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, 2)
 | 
			
		||||
		require.Equal(t, fmt.Sprintf("dashboards:uid:%s", dashboard.Uid), resolvedScopes[0])
 | 
			
		||||
		require.Equal(t, fmt.Sprintf("folders:uid:%s", folder.Uid), resolvedScopes[1])
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
 | 
			
		||||
		_, resolver := NewDashboardUIDScopeResolver(&FakeDashboardStore{})
 | 
			
		||||
		_, 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)
 | 
			
		||||
 | 
			
		||||
		dashboard := &models.Dashboard{Id: 1, FolderId: 0, Uid: "1"}
 | 
			
		||||
		store.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)
 | 
			
		||||
 | 
			
		||||
		require.Len(t, resolved, 2)
 | 
			
		||||
		require.Equal(t, "dashboards:uid:1", resolved[0])
 | 
			
		||||
		require.Equal(t, "folders:uid:general", resolved[1])
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,7 +53,7 @@ type Store interface {
 | 
			
		|||
	DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error
 | 
			
		||||
	DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *models.DeleteOrphanedProvisionedDashboardsCommand) error
 | 
			
		||||
	FindDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)
 | 
			
		||||
	GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error
 | 
			
		||||
	GetDashboard(ctx context.Context, query *models.GetDashboardQuery) (*models.Dashboard, error)
 | 
			
		||||
	GetDashboardAclInfoList(ctx context.Context, query *models.GetDashboardAclInfoListQuery) error
 | 
			
		||||
	GetDashboardUIDById(ctx context.Context, query *models.GetDashboardRefByIdQuery) error
 | 
			
		||||
	GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -832,8 +832,8 @@ func (d *DashboardStore) deleteAlertDefinition(dashboardId int64, sess *sqlstore
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
 | 
			
		||||
	return d.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
 | 
			
		||||
func (d *DashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) (*models.Dashboard, error) {
 | 
			
		||||
	err := d.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
 | 
			
		||||
		if query.Id == 0 && len(query.Slug) == 0 && len(query.Uid) == 0 {
 | 
			
		||||
			return models.ErrDashboardIdentifierNotSet
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -852,6 +852,8 @@ func (d *DashboardStore) GetDashboard(ctx context.Context, query *models.GetDash
 | 
			
		|||
		query.Result = &dashboard
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return query.Result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DashboardStore) GetDashboardUIDById(ctx context.Context, query *models.GetDashboardRefByIdQuery) error {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,7 +62,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
 | 
			
		|||
			OrgId: 1,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		_, err := dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
		require.Equal(t, query.Result.Title, "test dash 23")
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +79,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
 | 
			
		|||
			OrgId: 1,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		_, err := dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
		require.Equal(t, query.Result.Title, "test dash 23")
 | 
			
		||||
| 
						 | 
				
			
			@ -96,7 +96,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
 | 
			
		|||
			OrgId: 1,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		_, err := dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
		require.Equal(t, query.Result.Title, "test dash 23")
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +120,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
 | 
			
		|||
			OrgId: 1,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		_, err := dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		require.Equal(t, err, models.ErrDashboardIdentifierNotSet)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -202,7 +202,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
 | 
			
		|||
			OrgId: 1,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		_, err = dashboardStore.GetDashboard(context.Background(), &query)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
		require.Equal(t, query.Result.FolderId, int64(0))
 | 
			
		||||
		require.Equal(t, query.Result.CreatedBy, savedDash.CreatedBy)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,13 +38,17 @@ type DashboardServiceImpl struct {
 | 
			
		|||
	features             featuremgmt.FeatureToggles
 | 
			
		||||
	folderPermissions    accesscontrol.FolderPermissionsService
 | 
			
		||||
	dashboardPermissions accesscontrol.DashboardPermissionsService
 | 
			
		||||
	ac                   accesscontrol.AccessControl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ProvideDashboardService(
 | 
			
		||||
	cfg *setting.Cfg, store dashboards.Store, dashAlertExtractor alerting.DashAlertExtractor,
 | 
			
		||||
	features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
 | 
			
		||||
	dashboardPermissionsService accesscontrol.DashboardPermissionsService,
 | 
			
		||||
	dashboardPermissionsService accesscontrol.DashboardPermissionsService, ac accesscontrol.AccessControl,
 | 
			
		||||
) *DashboardServiceImpl {
 | 
			
		||||
	ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(store))
 | 
			
		||||
	ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(store))
 | 
			
		||||
 | 
			
		||||
	return &DashboardServiceImpl{
 | 
			
		||||
		cfg:                  cfg,
 | 
			
		||||
		log:                  log.New("dashboard-service"),
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +57,7 @@ func ProvideDashboardService(
 | 
			
		|||
		features:             features,
 | 
			
		||||
		folderPermissions:    folderPermissionsService,
 | 
			
		||||
		dashboardPermissions: dashboardPermissionsService,
 | 
			
		||||
		ac:                   ac,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -484,7 +489,8 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (dr *DashboardServiceImpl) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
 | 
			
		||||
	return dr.dashboardStore.GetDashboard(ctx, query)
 | 
			
		||||
	_, err := dr.dashboardStore.GetDashboard(ctx, query)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dr *DashboardServiceImpl) GetDashboardUIDById(ctx context.Context, query *models.GetDashboardRefByIdQuery) error {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
					res := callSaveWithResult(t, cmd, sc.sqlStore)
 | 
			
		||||
					require.NotNil(t, res)
 | 
			
		||||
 | 
			
		||||
					err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
					_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						OrgId: otherOrgId,
 | 
			
		||||
						Uid:   sc.savedDashInFolder.Uid,
 | 
			
		||||
					})
 | 
			
		||||
| 
						 | 
				
			
			@ -314,7 +314,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						res := callSaveWithResult(t, cmd, sc.sqlStore)
 | 
			
		||||
						require.NotNil(t, res)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    res.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -339,7 +339,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
						assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    res.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -364,7 +364,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id)
 | 
			
		||||
						assert.True(t, res.IsFolder)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    res.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -386,7 +386,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
						assert.Greater(t, res.Id, int64(0))
 | 
			
		||||
						assert.NotEmpty(t, res.Uid)
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    res.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -407,7 +407,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						res := callSaveWithResult(t, cmd, sc.sqlStore)
 | 
			
		||||
						require.NotNil(t, res)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    res.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -461,7 +461,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						res := callSaveWithResult(t, cmd, sc.sqlStore)
 | 
			
		||||
						require.NotNil(t, res)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    sc.savedDashInGeneralFolder.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -501,7 +501,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						res := callSaveWithResult(t, cmd, sc.sqlStore)
 | 
			
		||||
						require.NotNil(t, res)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    sc.savedDashInFolder.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -575,7 +575,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						res := callSaveWithResult(t, cmd, sc.sqlStore)
 | 
			
		||||
						require.NotNil(t, res)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    sc.savedDashInGeneralFolder.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -597,7 +597,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						res := callSaveWithResult(t, cmd, sc.sqlStore)
 | 
			
		||||
						require.NotNil(t, res)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    sc.savedDashInFolder.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -621,7 +621,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						assert.Equal(t, sc.savedDashInFolder.Id, res.Id)
 | 
			
		||||
						assert.Equal(t, "new-uid", res.Uid)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    sc.savedDashInFolder.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -661,7 +661,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						assert.Equal(t, sc.savedDashInFolder.Id, res.Id)
 | 
			
		||||
						assert.Equal(t, sc.savedDashInFolder.Uid, res.Uid)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    res.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -685,7 +685,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
 | 
			
		|||
						assert.Equal(t, sc.savedDashInGeneralFolder.Id, res.Id)
 | 
			
		||||
						assert.Equal(t, sc.savedDashInGeneralFolder.Uid, res.Uid)
 | 
			
		||||
 | 
			
		||||
						err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
						_, err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
 | 
			
		||||
							Id:    res.Id,
 | 
			
		||||
							OrgId: cmd.OrgId,
 | 
			
		||||
						})
 | 
			
		||||
| 
						 | 
				
			
			@ -817,6 +817,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
 | 
			
		|||
			featuremgmt.WithFeatures(),
 | 
			
		||||
			accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
			accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
			accesscontrolmock.New(),
 | 
			
		||||
		)
 | 
			
		||||
		guardian.InitLegacyGuardian(sqlStore, service)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -872,6 +873,7 @@ func callSaveWithResult(t *testing.T, cmd models.SaveDashboardCommand, sqlStore
 | 
			
		|||
		featuremgmt.WithFeatures(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.New(),
 | 
			
		||||
	)
 | 
			
		||||
	res, err := service.SaveDashboard(context.Background(), &dto, false)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -889,6 +891,7 @@ func callSaveWithError(cmd models.SaveDashboardCommand, sqlStore *sqlstore.SQLSt
 | 
			
		|||
		featuremgmt.WithFeatures(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.New(),
 | 
			
		||||
	)
 | 
			
		||||
	_, err := service.SaveDashboard(context.Background(), &dto, false)
 | 
			
		||||
	return err
 | 
			
		||||
| 
						 | 
				
			
			@ -922,7 +925,9 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto
 | 
			
		|||
	service := ProvideDashboardService(
 | 
			
		||||
		cfg, dashboardStore, &dummyDashAlertExtractor{},
 | 
			
		||||
		featuremgmt.WithFeatures(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.New(),
 | 
			
		||||
	)
 | 
			
		||||
	res, err := service.SaveDashboard(context.Background(), &dto, false)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -957,7 +962,9 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore *sqlstore.
 | 
			
		|||
	service := ProvideDashboardService(
 | 
			
		||||
		cfg, dashboardStore, &dummyDashAlertExtractor{},
 | 
			
		||||
		featuremgmt.WithFeatures(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.NewMockedPermissionsService(),
 | 
			
		||||
		accesscontrolmock.New(),
 | 
			
		||||
	)
 | 
			
		||||
	res, err := service.SaveDashboard(context.Background(), &dto, false)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ func (f *FolderServiceImpl) CreateFolder(ctx context.Context, user *models.Signe
 | 
			
		|||
 | 
			
		||||
func (f *FolderServiceImpl) UpdateFolder(ctx context.Context, user *models.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error {
 | 
			
		||||
	query := models.GetDashboardQuery{OrgId: orgID, Uid: existingUid}
 | 
			
		||||
	if err := f.dashboardStore.GetDashboard(ctx, &query); err != nil {
 | 
			
		||||
	if _, err := f.dashboardStore.GetDashboard(ctx, &query); err != nil {
 | 
			
		||||
		return toFolderError(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,18 +24,10 @@ var user = &models.SignedInUser{UserId: 1}
 | 
			
		|||
 | 
			
		||||
func TestIntegrationProvideFolderService(t *testing.T) {
 | 
			
		||||
	t.Run("should register scope resolvers", func(t *testing.T) {
 | 
			
		||||
		store := &dashboards.FakeDashboardStore{}
 | 
			
		||||
		cfg := setting.NewCfg()
 | 
			
		||||
		features := featuremgmt.WithFeatures()
 | 
			
		||||
		cfg.IsFeatureToggleEnabled = features.IsEnabled
 | 
			
		||||
		folderPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
		dashboardPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
		dashboardService := ProvideDashboardService(cfg, store, nil, features, folderPermissions, dashboardPermissions)
 | 
			
		||||
		ac := acmock.New()
 | 
			
		||||
 | 
			
		||||
		ProvideFolderService(
 | 
			
		||||
			cfg, dashboardService, store, nil, features, folderPermissions, ac,
 | 
			
		||||
		)
 | 
			
		||||
		ProvideFolderService(cfg, nil, nil, nil, nil, nil, ac)
 | 
			
		||||
 | 
			
		||||
		require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 2)
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +41,7 @@ func TestIntegrationFolderService(t *testing.T) {
 | 
			
		|||
		cfg.IsFeatureToggleEnabled = features.IsEnabled
 | 
			
		||||
		folderPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
		dashboardPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
		dashboardService := ProvideDashboardService(cfg, store, nil, features, folderPermissions, dashboardPermissions)
 | 
			
		||||
		dashboardService := ProvideDashboardService(cfg, store, nil, features, folderPermissions, dashboardPermissions, acmock.New())
 | 
			
		||||
 | 
			
		||||
		service := FolderServiceImpl{
 | 
			
		||||
			cfg:              cfg,
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +94,7 @@ func TestIntegrationFolderService(t *testing.T) {
 | 
			
		|||
					folder := args.Get(1).(*models.GetDashboardQuery)
 | 
			
		||||
					folder.Result = models.NewDashboard("dashboard-test")
 | 
			
		||||
					folder.Result.IsFolder = true
 | 
			
		||||
				}).Return(nil)
 | 
			
		||||
				}).Return(&models.Dashboard{}, nil)
 | 
			
		||||
				err := service.UpdateFolder(context.Background(), user, orgID, folderUID, &models.UpdateFolderCommand{
 | 
			
		||||
					Uid:   folderUID,
 | 
			
		||||
					Title: "Folder-TEST",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,17 +68,26 @@ func (_m *FakeDashboardStore) FindDashboards(ctx context.Context, query *models.
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// GetDashboard provides a mock function with given fields: ctx, query
 | 
			
		||||
func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
 | 
			
		||||
func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) (*models.Dashboard, error) {
 | 
			
		||||
	ret := _m.Called(ctx, query)
 | 
			
		||||
 | 
			
		||||
	var r0 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *models.GetDashboardQuery) error); ok {
 | 
			
		||||
	var r0 *models.Dashboard
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *models.GetDashboardQuery) *models.Dashboard); ok {
 | 
			
		||||
		r0 = rf(ctx, query)
 | 
			
		||||
	} else {
 | 
			
		||||
		r0 = ret.Error(0)
 | 
			
		||||
		if ret.Get(0) != nil {
 | 
			
		||||
			r0 = ret.Get(0).(*models.Dashboard)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(1).(func(context.Context, *models.GetDashboardQuery) error); ok {
 | 
			
		||||
		r1 = rf(ctx, query)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetDashboardAclInfoList provides a mock function with given fields: ctx, query
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -205,11 +205,12 @@ func createDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, user models.Sign
 | 
			
		|||
	features := featuremgmt.WithFeatures()
 | 
			
		||||
	cfg := setting.NewCfg()
 | 
			
		||||
	cfg.IsFeatureToggleEnabled = features.IsEnabled
 | 
			
		||||
	ac := acmock.New()
 | 
			
		||||
	folderPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
	dashboardPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
	service := dashboardservice.ProvideDashboardService(
 | 
			
		||||
		cfg, dashboardStore, dashAlertExtractor,
 | 
			
		||||
		features, folderPermissions, dashboardPermissions,
 | 
			
		||||
		features, folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
	)
 | 
			
		||||
	dashboard, err := service.SaveDashboard(context.Background(), dashItem, true)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -224,15 +225,15 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string
 | 
			
		|||
	cfg := setting.NewCfg()
 | 
			
		||||
	features := featuremgmt.WithFeatures()
 | 
			
		||||
	cfg.IsFeatureToggleEnabled = features.IsEnabled
 | 
			
		||||
	ac := acmock.New()
 | 
			
		||||
	folderPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
	dashboardPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
	dashboardStore := database.ProvideDashboardStore(sqlStore)
 | 
			
		||||
 | 
			
		||||
	d := dashboardservice.ProvideDashboardService(
 | 
			
		||||
		cfg, dashboardStore, nil,
 | 
			
		||||
		features, folderPermissions, dashboardPermissions,
 | 
			
		||||
		features, folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
	)
 | 
			
		||||
	ac := acmock.New()
 | 
			
		||||
	s := dashboardservice.ProvideFolderService(
 | 
			
		||||
		cfg, d, dashboardStore, nil,
 | 
			
		||||
		features, folderPermissions, ac,
 | 
			
		||||
| 
						 | 
				
			
			@ -326,14 +327,14 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
 | 
			
		|||
		features := featuremgmt.WithFeatures()
 | 
			
		||||
		cfg := setting.NewCfg()
 | 
			
		||||
		cfg.IsFeatureToggleEnabled = features.IsEnabled
 | 
			
		||||
		ac := acmock.New()
 | 
			
		||||
		folderPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
		dashboardPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
		dashboardService := dashboardservice.ProvideDashboardService(
 | 
			
		||||
			cfg, dashboardStore, nil,
 | 
			
		||||
			features, folderPermissions, dashboardPermissions,
 | 
			
		||||
			features, folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
		)
 | 
			
		||||
		guardian.InitLegacyGuardian(sqlStore, dashboardService)
 | 
			
		||||
		ac := acmock.New()
 | 
			
		||||
		service := LibraryElementService{
 | 
			
		||||
			Cfg:      cfg,
 | 
			
		||||
			SQLStore: sqlStore,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1370,9 +1370,10 @@ func createDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, user *models.Sig
 | 
			
		|||
	dashAlertService := alerting.ProvideDashAlertExtractorService(nil, nil, nil)
 | 
			
		||||
	cfg := setting.NewCfg()
 | 
			
		||||
	cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
 | 
			
		||||
	ac := acmock.New()
 | 
			
		||||
	service := dashboardservice.ProvideDashboardService(
 | 
			
		||||
		cfg, dashboardStore, dashAlertService,
 | 
			
		||||
		featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), acmock.NewMockedPermissionsService(),
 | 
			
		||||
		featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), acmock.NewMockedPermissionsService(), ac,
 | 
			
		||||
	)
 | 
			
		||||
	dashboard, err := service.SaveDashboard(context.Background(), dashItem, true)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -1391,7 +1392,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string
 | 
			
		|||
	folderPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
	dashboardPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
	dashboardStore := database.ProvideDashboardStore(sqlStore)
 | 
			
		||||
	d := dashboardservice.ProvideDashboardService(cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions)
 | 
			
		||||
	d := dashboardservice.ProvideDashboardService(cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac)
 | 
			
		||||
	s := dashboardservice.ProvideFolderService(cfg, d, dashboardStore, nil, features, folderPermissions, ac)
 | 
			
		||||
 | 
			
		||||
	t.Logf("Creating folder with title and UID %q", title)
 | 
			
		||||
| 
						 | 
				
			
			@ -1485,14 +1486,14 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
 | 
			
		|||
		dashboardStore := database.ProvideDashboardStore(sqlStore)
 | 
			
		||||
 | 
			
		||||
		features := featuremgmt.WithFeatures()
 | 
			
		||||
		ac := acmock.New()
 | 
			
		||||
		folderPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
		dashboardPermissions := acmock.NewMockedPermissionsService()
 | 
			
		||||
 | 
			
		||||
		dashboardService := dashboardservice.ProvideDashboardService(
 | 
			
		||||
			cfg, dashboardStore, &alerting.DashAlertExtractorService{},
 | 
			
		||||
			features, folderPermissions, dashboardPermissions,
 | 
			
		||||
			features, folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
		)
 | 
			
		||||
		ac := acmock.New()
 | 
			
		||||
 | 
			
		||||
		folderService := dashboardservice.ProvideFolderService(
 | 
			
		||||
			cfg, dashboardService, dashboardStore, nil,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ func SetupTestEnv(t *testing.T, baseInterval time.Duration) (*ngalert.AlertNG, *
 | 
			
		|||
 | 
			
		||||
	dashboardService := dashboardservice.ProvideDashboardService(
 | 
			
		||||
		cfg, dashboardStore, nil,
 | 
			
		||||
		features, folderPermissions, dashboardPermissions,
 | 
			
		||||
		features, folderPermissions, dashboardPermissions, ac,
 | 
			
		||||
	)
 | 
			
		||||
	folderService := dashboardservice.ProvideFolderService(
 | 
			
		||||
		cfg, dashboardService, dashboardStore, nil,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue