PublicDashboards: Delete on folder deletion (#99040)

This commit is contained in:
Ezequiel Victorero
2025-01-23 17:23:59 -03:00
committed by GitHub
parent fdbac6fb54
commit 3a94057ec8
37 changed files with 550 additions and 312 deletions
-6
View File
@@ -500,12 +500,6 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
"error", err)
}
// deletes all related public dashboard entities
err = hs.PublicDashboardsApi.PublicDashboardService.DeleteByDashboard(c.Req.Context(), dash)
if err != nil {
hs.log.Error("Failed to delete public dashboard")
}
err = hs.DashboardService.DeleteDashboard(c.Req.Context(), dash.ID, dash.UID, c.SignedInUser.GetOrgID())
if err != nil {
var dashboardErr dashboards.DashboardErr
+4 -6
View File
@@ -272,12 +272,10 @@ func TestHTTPServer_DeleteDashboardByUID_AccessControl(t *testing.T) {
hs.LibraryPanelService = &mockLibraryPanelService{}
hs.LibraryElementService = &libraryelementsfake.LibraryElementService{}
pubDashService := publicdashboards.NewFakePublicDashboardService(t)
pubDashService.On("DeleteByDashboard", mock.Anything, mock.Anything).Return(nil).Maybe()
middleware := publicdashboards.NewFakePublicDashboardMiddleware(t)
license := licensingtest.NewFakeLicensing()
license.On("FeatureEnabled", publicdashboardModels.FeaturePublicDashboardsEmailSharing).Return(false)
hs.PublicDashboardsApi = api.ProvideApi(pubDashService, nil, hs.AccessControl, featuremgmt.WithFeatures(), middleware, hs.Cfg, license)
hs.PublicDashboardsApi = api.ProvideApi(nil, nil, hs.AccessControl, featuremgmt.WithFeatures(), middleware, hs.Cfg, license)
guardian.InitAccessControlGuardian(hs.Cfg, hs.AccessControl, hs.DashboardService, hs.folderService, log.NewNopLogger())
})
@@ -833,11 +831,11 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
quotaService := quotatest.New(false, nil)
folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()),
dashboardStore, folderStore, db, features,
supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
if dashboardService == nil {
dashboardService, err = service.ProvideDashboardServiceImpl(
cfg, dashboardStore, folderStore, features, folderPermissions,
ac, folderSvc, fStore, nil, nil, nil, nil, quotaService, nil,
ac, folderSvc, fStore, nil, nil, nil, nil, quotaService, nil, nil,
)
require.NoError(t, err)
dashboardService.(dashboards.PermissionsRegistrationService).RegisterDashboardPermissions(dashboardPermissions)
@@ -845,7 +843,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
dashboardProvisioningService, err := service.ProvideDashboardServiceImpl(
cfg, dashboardStore, folderStore, features, folderPermissions,
ac, folderSvc, fStore, nil, nil, nil, nil, quotaService, nil,
ac, folderSvc, fStore, nil, nil, nil, nil, quotaService, nil, nil,
)
require.NoError(t, err)
+2 -2
View File
@@ -461,7 +461,7 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
actionSets := resourcepermissions.NewActionSetService(features)
fStore := folderimpl.ProvideStore(sc.db)
folderServiceWithFlagOn := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore,
folderStore, sc.db, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderStore, sc.db, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
acSvc := acimpl.ProvideOSSService(
sc.cfg, acdb.ProvideService(sc.db), actionSets, localcache.ProvideService(),
features, tracing.InitializeTracerForTest(), zanzana.NewNoopClient(), sc.db, permreg.ProvidePermissionRegistry(), nil, folderServiceWithFlagOn,
@@ -472,7 +472,7 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
dashboardSvc, err := dashboardservice.ProvideDashboardServiceImpl(
sc.cfg, dashStore, folderStore,
features, folderPermissions, ac,
folderServiceWithFlagOn, fStore, nil, nil, nil, nil, quotaSrv, nil,
folderServiceWithFlagOn, fStore, nil, nil, nil, nil, quotaSrv, nil, nil,
)
require.NoError(b, err)
@@ -49,7 +49,7 @@ func ProvideFolderPermissions(
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
fService := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()),
dashboardStore, folderStore, sqlStore, features,
supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
acSvc := acimpl.ProvideOSSService(
cfg, acdb.ProvideService(sqlStore), actionSets, localcache.ProvideService(),
@@ -49,9 +49,9 @@ func TestIntegrationAuthorize(t *testing.T) {
ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
folderSvc := folderimpl.ProvideService(fStore, accesscontrolmock.New(), bus.ProvideBus(tracing.InitializeTracerForTest()),
dashStore, folderStore, sql, featuremgmt.WithFeatures(),
supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
dashSvc, err := dashboardsservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(),
ac, folderSvc, fStore, nil, nil, nil, nil, quotatest.New(false, nil), nil)
ac, folderSvc, fStore, nil, nil, nil, nil, quotatest.New(false, nil), nil, nil)
require.NoError(t, err)
dashSvc.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService())
@@ -61,9 +61,9 @@ func TestIntegrationAnnotationListingWithRBAC(t *testing.T) {
ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
folderSvc := folderimpl.ProvideService(fStore, accesscontrolmock.New(), bus.ProvideBus(tracing.InitializeTracerForTest()),
dashStore, folderStore, sql, featuremgmt.WithFeatures(),
supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
dashSvc, err := dashboardsservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(),
ac, folderSvc, fStore, nil, nil, nil, nil, quotatest.New(false, nil), nil)
ac, folderSvc, fStore, nil, nil, nil, nil, quotatest.New(false, nil), nil, nil)
require.NoError(t, err)
dashSvc.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService())
repo := ProvideService(sql, cfg, features, tagService, tracing.InitializeTracerForTest(), ruleStore, dashSvc)
@@ -243,9 +243,9 @@ func TestIntegrationAnnotationListingWithInheritedRBAC(t *testing.T) {
fStore := folderimpl.ProvideStore(sql)
folderStore := folderimpl.ProvideDashboardFolderStore(sql)
folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore,
folderStore, sql, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderStore, sql, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
dashSvc, err := dashboardsservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, features, accesscontrolmock.NewMockedPermissionsService(),
ac, folderSvc, fStore, nil, nil, nil, nil, quotatest.New(false, nil), nil)
ac, folderSvc, fStore, nil, nil, nil, nil, quotatest.New(false, nil), nil, nil)
require.NoError(t, err)
dashSvc.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService())
cfg.AnnotationMaximumTagsLength = 60
@@ -300,7 +300,7 @@ func TestIntegrationDashboardInheritedFolderRBAC(t *testing.T) {
})
folderStore := folderimpl.ProvideStore(sqlStore)
folderSvc := folderimpl.ProvideService(folderStore, mock.New(), bus.ProvideBus(tracer), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(sqlStore), sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderSvc := folderimpl.ProvideService(folderStore, mock.New(), bus.ProvideBus(tracer), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(sqlStore), sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
parentUID := ""
for i := 0; ; i++ {
@@ -902,7 +902,7 @@ func TestIntegrationFindDashboardsByTitle(t *testing.T) {
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
fStore := folderimpl.ProvideStore(sqlStore)
folderServiceWithFlagOn := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore,
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
user := &user.SignedInUser{
OrgID: 1,
@@ -1021,7 +1021,7 @@ func TestIntegrationFindDashboardsByFolder(t *testing.T) {
fStore := folderimpl.ProvideStore(sqlStore)
folderServiceWithFlagOn := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore,
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
user := &user.SignedInUser{
OrgID: 1,
+5
View File
@@ -360,6 +360,11 @@ type DeleteDashboardsInFolderRequest struct {
OrgID int64
}
type GetAllDashboardsInFolderRequest struct {
FolderUIDs []string
OrgID int64
}
//
// DASHBOARD ACL
//
@@ -42,6 +42,7 @@ import (
"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/publicdashboards"
"github.com/grafana/grafana/pkg/services/quota"
"github.com/grafana/grafana/pkg/services/search/model"
"github.com/grafana/grafana/pkg/services/store/entity"
@@ -71,19 +72,20 @@ var (
)
type DashboardServiceImpl struct {
cfg *setting.Cfg
log log.Logger
dashboardStore dashboards.Store
folderStore folder.FolderStore
folderService folder.Service
userService user.Service
orgService org.Service
features featuremgmt.FeatureToggles
folderPermissions accesscontrol.FolderPermissionsService
dashboardPermissions accesscontrol.DashboardPermissionsService
ac accesscontrol.AccessControl
k8sclient client.K8sHandler
metrics *dashboardsMetrics
cfg *setting.Cfg
log log.Logger
dashboardStore dashboards.Store
folderStore folder.FolderStore
folderService folder.Service
userService user.Service
orgService org.Service
features featuremgmt.FeatureToggles
folderPermissions accesscontrol.FolderPermissionsService
dashboardPermissions accesscontrol.DashboardPermissionsService
ac accesscontrol.AccessControl
k8sclient client.K8sHandler
metrics *dashboardsMetrics
publicDashboardService publicdashboards.ServiceWrapper
dashboardPermissionsReady chan struct{}
}
@@ -96,7 +98,7 @@ func ProvideDashboardServiceImpl(
features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
ac accesscontrol.AccessControl, folderSvc folder.Service, fStore folder.Store, r prometheus.Registerer,
restConfigProvider apiserver.RestConfigProvider, userService user.Service, unified resource.ResourceClient,
quotaService quota.Service, orgService org.Service,
quotaService quota.Service, orgService org.Service, publicDashboardService publicdashboards.ServiceWrapper,
) (*DashboardServiceImpl, error) {
k8sHandler := client.NewK8sHandler(request.GetNamespaceMapper(cfg), v0alpha1.DashboardResourceInfo.GroupVersionResource(), restConfigProvider, unified)
@@ -114,6 +116,7 @@ func ProvideDashboardServiceImpl(
k8sclient: k8sHandler,
metrics: newDashboardsMetrics(r),
dashboardPermissionsReady: make(chan struct{}),
publicDashboardService: publicDashboardService,
}
defaultLimits, err := readQuotaConfig(cfg)
@@ -879,7 +882,13 @@ func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId
if err != nil {
return err
}
// cleanup things related to dashboards that are not stored in unistore yet
err = dr.publicDashboardService.DeleteByDashboardUIDs(ctx, orgId, []string{dashboardUID})
if err != nil {
return err
}
return dr.dashboardStore.CleanupAfterDelete(ctx, cmd)
}
@@ -894,6 +903,12 @@ func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId
}
}
// deletes all related public dashboard entities
err := dr.publicDashboardService.DeleteByDashboardUIDs(ctx, orgId, []string{dashboardUID})
if err != nil {
return err
}
return dr.dashboardStore.DeleteDashboard(ctx, cmd)
}
@@ -1389,6 +1404,22 @@ func (dr *DashboardServiceImpl) DeleteInFolders(ctx context.Context, orgID int64
return dr.dashboardStore.SoftDeleteDashboardsInFolders(ctx, orgID, folderUIDs)
}
// We need a list of dashboard uids inside the folder to delete related public dashboards
dashes, err := dr.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{SignedInUser: u, FolderUIDs: folderUIDs, OrgId: orgID})
if err != nil {
return folder.ErrInternal.Errorf("failed to fetch dashboards: %w", err)
}
dashboardUIDs := make([]string, 0, len(dashes))
for _, dashboard := range dashes {
dashboardUIDs = append(dashboardUIDs, dashboard.UID)
}
err = dr.publicDashboardService.DeleteByDashboardUIDs(ctx, orgID, dashboardUIDs)
if err != nil {
return err
}
return dr.dashboardStore.DeleteDashboardsInFolders(ctx, &dashboards.DeleteDashboardsInFolderRequest{FolderUIDs: folderUIDs, OrgID: orgID})
}
@@ -24,6 +24,7 @@ import (
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
@@ -878,8 +879,9 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
folderPermissions := accesscontrolmock.NewMockedPermissionsService()
folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
tracer := tracing.InitializeTracerForTest()
publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
folderStore2 := folderimpl.ProvideStore(sqlStore)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), publicDashboardFakeService, cfg, nil, tracer)
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
dashboardService, err := ProvideDashboardServiceImpl(
cfg, dashboardStore, folderStore,
@@ -894,6 +896,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
nil,
quotaService,
nil,
nil,
)
dashboardService.RegisterDashboardPermissions(dashboardPermissions)
require.NoError(t, err)
@@ -950,8 +953,9 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt
folderPermissions := accesscontrolmock.NewMockedPermissionsService()
folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
tracer := tracing.InitializeTracerForTest()
publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
folderStore2 := folderimpl.ProvideStore(sqlStore)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), publicDashboardFakeService, cfg, nil, tracer)
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
dashboardPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
service, err := ProvideDashboardServiceImpl(
@@ -967,6 +971,7 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt
nil,
quotaService,
nil,
nil,
)
require.NoError(t, err)
service.RegisterDashboardPermissions(dashboardPermissions)
@@ -985,8 +990,9 @@ func callSaveWithError(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSto
require.NoError(t, err)
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
tracer := tracing.InitializeTracerForTest()
publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
folderStore2 := folderimpl.ProvideStore(sqlStore)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), publicDashboardFakeService, cfg, nil, tracer)
service, err := ProvideDashboardServiceImpl(
cfg, dashboardStore, folderStore,
featuremgmt.WithFeatures(),
@@ -1000,6 +1006,7 @@ func callSaveWithError(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSto
nil,
quotaService,
nil,
nil,
)
require.NoError(t, err)
service.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService())
@@ -1037,8 +1044,9 @@ func saveTestDashboard(t *testing.T, title string, orgID int64, folderUID string
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
dashboardPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
tracer := tracing.InitializeTracerForTest()
publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
folderStore2 := folderimpl.ProvideStore(sqlStore)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), publicDashboardFakeService, cfg, nil, tracer)
service, err := ProvideDashboardServiceImpl(
cfg, dashboardStore, folderStore,
features,
@@ -1052,6 +1060,7 @@ func saveTestDashboard(t *testing.T, title string, orgID int64, folderUID string
nil,
quotaService,
nil,
nil,
)
require.NoError(t, err)
service.RegisterDashboardPermissions(dashboardPermissions)
@@ -1095,8 +1104,9 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
folderPermissions := accesscontrolmock.NewMockedPermissionsService()
tracer := tracing.InitializeTracerForTest()
publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
folderStore2 := folderimpl.ProvideStore(sqlStore)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), publicDashboardFakeService, cfg, nil, tracer)
folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
service, err := ProvideDashboardServiceImpl(
cfg, dashboardStore, folderStore,
@@ -1111,6 +1121,7 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da
nil,
quotaService,
nil,
nil,
)
require.NoError(t, err)
service.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService())
@@ -22,6 +22,7 @@ import (
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/org/orgtest"
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/quota"
"github.com/grafana/grafana/pkg/services/search/model"
"github.com/grafana/grafana/pkg/services/user"
@@ -35,15 +36,17 @@ import (
func TestDashboardService(t *testing.T) {
t.Run("Dashboard service tests", func(t *testing.T) {
fakeStore := dashboards.FakeDashboardStore{}
fakePublicDashboardService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
defer fakeStore.AssertExpectations(t)
folderSvc := foldertest.NewFakeService()
service := &DashboardServiceImpl{
cfg: setting.NewCfg(),
log: log.New("test.logger"),
dashboardStore: &fakeStore,
folderService: folderSvc,
features: featuremgmt.WithFeatures(),
cfg: setting.NewCfg(),
log: log.New("test.logger"),
dashboardStore: &fakeStore,
folderService: folderSvc,
features: featuremgmt.WithFeatures(),
publicDashboardService: fakePublicDashboardService,
}
folderStore := foldertest.FakeFolderStore{}
folderStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(nil, dashboards.ErrFolderNotFound).Once()
@@ -197,6 +200,7 @@ func TestDashboardService(t *testing.T) {
t.Run("DeleteProvisionedDashboard should delete it", func(t *testing.T) {
args := &dashboards.DeleteDashboardCommand{OrgID: 1, ID: 1}
fakeStore.On("DeleteDashboard", mock.Anything, args).Return(nil).Once()
fakePublicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
err := service.DeleteProvisionedDashboard(context.Background(), 1, 1)
require.NoError(t, err)
})
@@ -212,6 +216,7 @@ func TestDashboardService(t *testing.T) {
t.Run("DeleteProvisionedDashboard should delete the dashboard", func(t *testing.T) {
args := &dashboards.DeleteDashboardCommand{OrgID: 1, ID: 1}
fakeStore.On("DeleteDashboard", mock.Anything, args).Return(nil).Once()
fakePublicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
err := service.DeleteProvisionedDashboard(context.Background(), 1, 1)
require.NoError(t, err)
})
@@ -220,6 +225,7 @@ func TestDashboardService(t *testing.T) {
args := &dashboards.DeleteDashboardCommand{OrgID: 1, ID: 1}
fakeStore.On("DeleteDashboard", mock.Anything, args).Return(nil).Once()
fakeStore.On("GetProvisionedDataByDashboardID", mock.Anything, mock.AnythingOfType("int64")).Return(nil, nil).Once()
fakePublicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
err := service.DeleteDashboard(context.Background(), 1, "", 1)
require.NoError(t, err)
})
@@ -240,6 +246,8 @@ func TestDashboardService(t *testing.T) {
t.Run("Delete dashboards in folder", func(t *testing.T) {
args := &dashboards.DeleteDashboardsInFolderRequest{OrgID: 1, FolderUIDs: []string{"uid"}}
fakeStore.On("DeleteDashboardsInFolders", mock.Anything, args).Return(nil).Once()
fakeStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{}, nil).Once()
fakePublicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
err := service.DeleteInFolders(context.Background(), 1, []string{"uid"}, nil)
require.NoError(t, err)
})
@@ -775,6 +783,7 @@ func TestGetProvisionedDashboardDataByDashboardUID(t *testing.T) {
func TestDeleteOrphanedProvisionedDashboards(t *testing.T) {
fakeStore := dashboards.FakeDashboardStore{}
fakePublicDashboardService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
defer fakeStore.AssertExpectations(t)
service := &DashboardServiceImpl{
cfg: setting.NewCfg(),
@@ -782,6 +791,7 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) {
orgService: &orgtest.FakeOrgService{
ExpectedOrgs: []*org.OrgDTO{{ID: 1}, {ID: 2}},
},
publicDashboardService: fakePublicDashboardService,
}
t.Run("Should fallback to dashboard store if Kubernetes feature flags are not enabled", func(t *testing.T) {
@@ -801,6 +811,7 @@ func TestDeleteOrphanedProvisionedDashboards(t *testing.T) {
k8sCliMock.On("Delete", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
fakeStore.On("CleanupAfterDelete", mock.Anything, &dashboards.DeleteDashboardCommand{UID: "uid", OrgID: 1}).Return(nil).Once()
fakeStore.On("CleanupAfterDelete", mock.Anything, &dashboards.DeleteDashboardCommand{UID: "uid3", OrgID: 2}).Return(nil).Once()
fakePublicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil)
k8sCliMock.On("Get", mock.Anything, "uid", mock.Anything, mock.Anything).Return(&unstructured.Unstructured{Object: map[string]any{
"metadata": map[string]any{
"name": "uid",
@@ -1201,16 +1212,20 @@ func TestSaveDashboard(t *testing.T) {
func TestDeleteDashboard(t *testing.T) {
fakeStore := dashboards.FakeDashboardStore{}
fakePublicDashboardService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
defer fakeStore.AssertExpectations(t)
service := &DashboardServiceImpl{
cfg: setting.NewCfg(),
dashboardStore: &fakeStore,
cfg: setting.NewCfg(),
dashboardStore: &fakeStore,
publicDashboardService: fakePublicDashboardService,
}
t.Run("Should fallback to dashboard store if Kubernetes feature flags are not enabled", func(t *testing.T) {
service.features = featuremgmt.WithFeatures()
fakeStore.On("DeleteDashboard", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
fakeStore.On("GetProvisionedDataByDashboardID", mock.Anything, mock.Anything).Return(nil, nil).Once()
fakePublicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
err := service.DeleteDashboard(context.Background(), 1, "uid", 1)
require.NoError(t, err)
fakeStore.AssertExpectations(t)
@@ -1220,6 +1235,7 @@ func TestDeleteDashboard(t *testing.T) {
ctx, k8sCliMock := setupK8sDashboardTests(service)
k8sCliMock.On("Delete", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
fakeStore.On("CleanupAfterDelete", mock.Anything, mock.Anything).Return(nil).Once()
fakePublicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
err := service.DeleteDashboard(ctx, 1, "uid", 1)
require.NoError(t, err)
@@ -1230,6 +1246,7 @@ func TestDeleteDashboard(t *testing.T) {
ctx, k8sCliMock := setupK8sDashboardTests(service)
k8sCliMock.On("Delete", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
fakeStore.On("CleanupAfterDelete", mock.Anything, mock.Anything).Return(nil).Once()
fakePublicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{
Results: &resource.ResourceTable{
Columns: []*resource.ResourceTableColumnDefinition{
+37 -37
View File
@@ -18,6 +18,24 @@ type FakeDashboardStore struct {
mock.Mock
}
// CleanupAfterDelete provides a mock function with given fields: ctx, cmd
func (_m *FakeDashboardStore) CleanupAfterDelete(ctx context.Context, cmd *DeleteDashboardCommand) error {
ret := _m.Called(ctx, cmd)
if len(ret) == 0 {
panic("no return value specified for CleanupAfterDelete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *DeleteDashboardCommand) error); ok {
r0 = rf(ctx, cmd)
} else {
r0 = ret.Error(0)
}
return r0
}
// Count provides a mock function with given fields: _a0, _a1
func (_m *FakeDashboardStore) Count(_a0 context.Context, _a1 *quota.ScopeParameters) (*quota.Map, error) {
ret := _m.Called(_a0, _a1)
@@ -106,6 +124,24 @@ func (_m *FakeDashboardStore) CountDashboardsInFolders(ctx context.Context, requ
return r0, r1
}
// DeleteAllDashboards provides a mock function with given fields: ctx, orgID
func (_m *FakeDashboardStore) DeleteAllDashboards(ctx context.Context, orgID int64) error {
ret := _m.Called(ctx, orgID)
if len(ret) == 0 {
panic("no return value specified for DeleteAllDashboards")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, orgID)
} else {
r0 = ret.Error(0)
}
return r0
}
// DeleteDashboard provides a mock function with given fields: ctx, cmd
func (_m *FakeDashboardStore) DeleteDashboard(ctx context.Context, cmd *DeleteDashboardCommand) error {
ret := _m.Called(ctx, cmd)
@@ -124,42 +160,6 @@ func (_m *FakeDashboardStore) DeleteDashboard(ctx context.Context, cmd *DeleteDa
return r0
}
// CleanupAfterDelete provides a mock function with given fields: ctx, cmd
func (_m *FakeDashboardStore) CleanupAfterDelete(ctx context.Context, cmd *DeleteDashboardCommand) error {
ret := _m.Called(ctx, cmd)
if len(ret) == 0 {
panic("no return value specified for CleanupAfterDelete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *DeleteDashboardCommand) error); ok {
r0 = rf(ctx, cmd)
} else {
r0 = ret.Error(0)
}
return r0
}
// DeleteAllDashboards provides a mock function with given fields: ctx, orgID
func (_m *FakeDashboardStore) DeleteAllDashboards(ctx context.Context, orgID int64) error {
ret := _m.Called(ctx, orgID)
if len(ret) == 0 {
panic("no return value specified for DeleteDashboard")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, orgID)
} else {
r0 = ret.Error(0)
}
return r0
}
// DeleteDashboardsInFolders provides a mock function with given fields: ctx, request
func (_m *FakeDashboardStore) DeleteDashboardsInFolders(ctx context.Context, request *DeleteDashboardsInFolderRequest) error {
ret := _m.Called(ctx, request)
@@ -256,7 +256,7 @@ func (_m *FakeDashboardStore) GetAllDashboards(ctx context.Context) ([]*Dashboar
return r0, r1
}
// GetAllDashboardsByOrgId provides a mock function with given fields: ctx
// GetAllDashboardsByOrgId provides a mock function with given fields: ctx, orgID
func (_m *FakeDashboardStore) GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*Dashboard, error) {
ret := _m.Called(ctx, orgID)
@@ -115,6 +115,7 @@ func TestValidateDashboardExists(t *testing.T) {
nil,
quotatest.New(false, nil),
nil,
nil,
)
require.NoError(t, err)
s := ProvideService(dsStore, secretsService, dashSvc)
+46 -20
View File
@@ -33,6 +33,7 @@ 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/publicdashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/services/store/entity"
@@ -46,15 +47,16 @@ import (
const FULLPATH_SEPARATOR = "/"
type Service struct {
store folder.Store
unifiedStore folder.Store
db db.DB
log *slog.Logger
dashboardStore dashboards.Store
dashboardFolderStore folder.FolderStore
features featuremgmt.FeatureToggles
accessControl accesscontrol.AccessControl
k8sclient folderK8sHandler
store folder.Store
unifiedStore folder.Store
db db.DB
log *slog.Logger
dashboardStore dashboards.Store
dashboardFolderStore folder.FolderStore
features featuremgmt.FeatureToggles
accessControl accesscontrol.AccessControl
k8sclient folderK8sHandler
publicDashboardService publicdashboards.ServiceWrapper
// 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.
bus bus.Bus
@@ -74,22 +76,24 @@ func ProvideService(
db db.DB, // DB for the (new) nested folder store
features featuremgmt.FeatureToggles,
supportBundles supportbundles.Service,
publicDashboardService publicdashboards.ServiceWrapper,
cfg *setting.Cfg,
r prometheus.Registerer,
tracer tracing.Tracer,
) *Service {
srv := &Service{
log: slog.Default().With("logger", "folder-service"),
dashboardStore: dashboardStore,
dashboardFolderStore: folderStore,
store: store,
features: features,
accessControl: ac,
bus: bus,
db: db,
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(r),
tracer: tracer,
log: slog.Default().With("logger", "folder-service"),
dashboardStore: dashboardStore,
dashboardFolderStore: folderStore,
store: store,
features: features,
accessControl: ac,
bus: bus,
db: db,
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(r),
tracer: tracer,
publicDashboardService: publicDashboardService,
}
srv.DBMigration(db)
@@ -1008,7 +1012,28 @@ func (s *Service) deleteChildrenInFolder(ctx context.Context, orgID int64, folde
}
func (s *Service) legacyDelete(ctx context.Context, cmd *folder.DeleteFolderCommand, folderUIDs []string) error {
// if dashboard restore is on we don't delete public dashboards, the hard delete will take care of it later
if !s.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
// We need a list of dashboard uids inside the folder to delete related public dashboards
dashes, err := s.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{SignedInUser: cmd.SignedInUser, FolderUIDs: folderUIDs, OrgId: cmd.OrgID})
if err != nil {
return folder.ErrInternal.Errorf("failed to fetch dashboards: %w", err)
}
dashboardUIDs := make([]string, 0, len(dashes))
for _, dashboard := range dashes {
dashboardUIDs = append(dashboardUIDs, dashboard.UID)
}
// Delete all public dashboards in the folders
err = s.publicDashboardService.DeleteByDashboardUIDs(ctx, cmd.OrgID, dashboardUIDs)
if err != nil {
return folder.ErrInternal.Errorf("failed to delete public dashboards: %w", err)
}
}
// TODO use bulk delete
// Delete all dashboards in the folders
for _, folderUID := range folderUIDs {
// nolint:staticcheck
deleteCmd := dashboards.DeleteDashboardCommand{OrgID: cmd.OrgID, UID: folderUID, ForceDeleteFolderRules: cmd.ForceDeleteRules}
@@ -1016,6 +1041,7 @@ func (s *Service) legacyDelete(ctx context.Context, cmd *folder.DeleteFolderComm
return toFolderError(err)
}
}
return nil
}
+58 -45
View File
@@ -41,6 +41,7 @@ import (
"github.com/grafana/grafana/pkg/services/ngalert/models"
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/store/entity"
@@ -64,7 +65,7 @@ func TestIntegrationProvideFolderService(t *testing.T) {
db, cfg := db.InitTestDBWithCfg(t)
store := ProvideStore(db)
ProvideService(store, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), nil, nil, db,
featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 2)
})
@@ -80,7 +81,7 @@ func TestIntegrationFolderService(t *testing.T) {
nestedFolderStore := ProvideStore(db)
folderStore := foldertest.NewFakeFolderStore(t)
publicDashboardService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
features := featuremgmt.WithFeatures()
alertingStore := ngstore.DBstore{
@@ -91,17 +92,18 @@ func TestIntegrationFolderService(t *testing.T) {
}
service := &Service{
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
dashboardStore: dashStore,
dashboardFolderStore: folderStore,
store: nestedFolderStore,
features: features,
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
db: db,
accessControl: acimpl.ProvideAccessControl(features),
metrics: newFoldersMetrics(nil),
registry: make(map[string]folder.RegistryService),
tracer: tracing.InitializeTracerForTest(),
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
dashboardStore: dashStore,
dashboardFolderStore: folderStore,
store: nestedFolderStore,
publicDashboardService: publicDashboardService,
features: features,
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
db: db,
accessControl: acimpl.ProvideAccessControl(features),
metrics: newFoldersMetrics(nil),
registry: make(map[string]folder.RegistryService),
tracer: tracing.InitializeTracerForTest(),
}
require.NoError(t, service.RegisterService(alertingStore))
@@ -263,11 +265,13 @@ func TestIntegrationFolderService(t *testing.T) {
f := folder.NewFolder(util.GenerateShortUID(), "")
f.UID = util.GenerateShortUID()
folderStore.On("GetFolderByUID", mock.Anything, orgID, f.UID).Return(f, nil)
publicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
var actualCmd *dashboards.DeleteDashboardCommand
dashStore.On("DeleteDashboard", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
actualCmd = args.Get(1).(*dashboards.DeleteDashboardCommand)
}).Return(nil).Once()
dashStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{}, nil).Once()
expectedForceDeleteRules := rand.Int63()%2 == 0
err := service.Delete(context.Background(), &folder.DeleteFolderCommand{
@@ -427,22 +431,24 @@ func TestIntegrationNestedFolderService(t *testing.T) {
dashStore, err := database.ProvideDashboardStore(db, cfg, featuresFlagOn, tagimpl.ProvideService(db))
require.NoError(t, err)
nestedFolderStore := ProvideStore(db)
publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
b := bus.ProvideBus(tracing.InitializeTracerForTest())
ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
serviceWithFlagOn := &Service{
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
dashboardStore: dashStore,
dashboardFolderStore: folderStore,
store: nestedFolderStore,
features: featuresFlagOn,
bus: b,
db: db,
accessControl: ac,
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(nil),
tracer: tracing.InitializeTracerForTest(),
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
dashboardStore: dashStore,
dashboardFolderStore: folderStore,
store: nestedFolderStore,
features: featuresFlagOn,
bus: b,
db: db,
accessControl: ac,
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(nil),
tracer: tracing.InitializeTracerForTest(),
publicDashboardService: publicDashboardFakeService,
}
signedInUser := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{
@@ -485,8 +491,9 @@ func TestIntegrationNestedFolderService(t *testing.T) {
// CanEditValue is required to create library elements
CanEditValue: true,
})
publicDashboardFakeService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil)
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuresFlagOn, folderPermissions, ac, serviceWithFlagOn, nestedFolderStore, nil, nil, nil, nil, quotaService, nil)
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuresFlagOn, folderPermissions, ac, serviceWithFlagOn, nestedFolderStore, nil, nil, nil, nil, quotaService, nil, publicDashboardFakeService)
require.NoError(t, err)
dashSrv.RegisterDashboardPermissions(dashboardPermissions)
@@ -548,16 +555,17 @@ func TestIntegrationNestedFolderService(t *testing.T) {
nestedFolderStore := ProvideStore(db)
serviceWithFlagOff := &Service{
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
dashboardStore: dashStore,
dashboardFolderStore: folderStore,
store: nestedFolderStore,
features: featuresFlagOff,
bus: b,
db: db,
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(nil),
tracer: tracing.InitializeTracerForTest(),
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
dashboardStore: dashStore,
dashboardFolderStore: folderStore,
store: nestedFolderStore,
features: featuresFlagOff,
bus: b,
db: db,
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(nil),
tracer: tracing.InitializeTracerForTest(),
publicDashboardService: publicDashboardFakeService,
}
origNewGuardian := guardian.New
@@ -568,8 +576,10 @@ func TestIntegrationNestedFolderService(t *testing.T) {
CanEditValue: true,
})
publicDashboardFakeService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil)
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuresFlagOff,
folderPermissions, ac, serviceWithFlagOff, nestedFolderStore, nil, nil, nil, nil, quotaService, nil)
folderPermissions, ac, serviceWithFlagOff, nestedFolderStore, nil, nil, nil, nil, quotaService, nil, publicDashboardFakeService)
require.NoError(t, err)
dashSrv.RegisterDashboardPermissions(dashboardPermissions)
alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOff, db, serviceWithFlagOff, dashSrv, ac, b)
@@ -628,14 +638,15 @@ func TestIntegrationNestedFolderService(t *testing.T) {
t.Run("Should delete folders", func(t *testing.T) {
featuresFlagOff := featuremgmt.WithFeatures()
serviceWithFlagOff := &Service{
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
dashboardFolderStore: folderStore,
features: featuresFlagOff,
bus: b,
db: db,
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(nil),
tracer: tracing.InitializeTracerForTest(),
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
dashboardFolderStore: folderStore,
features: featuresFlagOff,
bus: b,
db: db,
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(nil),
tracer: tracing.InitializeTracerForTest(),
publicDashboardService: publicDashboardFakeService,
}
testCases := []struct {
@@ -713,8 +724,9 @@ func TestIntegrationNestedFolderService(t *testing.T) {
nestedFolderStore := ProvideStore(db)
tc.service.dashboardStore = dashStore
tc.service.store = nestedFolderStore
publicDashboardFakeService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil)
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, tc.featuresFlag, folderPermissions, ac, tc.service, tc.service.store, nil, nil, nil, nil, quotaService, nil)
dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, tc.featuresFlag, folderPermissions, ac, tc.service, tc.service.store, nil, nil, nil, nil, quotaService, nil, publicDashboardFakeService)
require.NoError(t, err)
dashSrv.RegisterDashboardPermissions(dashboardPermissions)
@@ -1502,6 +1514,7 @@ func TestIntegrationNestedFolderSharedWithMe(t *testing.T) {
nil,
quotaService,
nil,
nil,
)
require.NoError(t, err)
dashboardService.RegisterDashboardPermissions(dashboardPermissions)
@@ -586,6 +586,26 @@ func (s *Service) deleteFromApiServer(ctx context.Context, cmd *folder.DeleteFol
if alertRulesInFolder > 0 {
return folder.ErrFolderNotEmpty.Errorf("folder contains %d alert rules", alertRulesInFolder)
}
// if dashboard restore is on we don't delete public dashboards, the hard delete will take care of it later
if !s.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
// We need a list of dashboard uids inside the folder to delete related public dashboards
dashes, err := s.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{SignedInUser: cmd.SignedInUser, FolderUIDs: folders, OrgId: cmd.OrgID})
if err != nil {
return folder.ErrInternal.Errorf("failed to fetch dashboards: %w", err)
}
dashboardUIDs := make([]string, 0, len(dashes))
for _, dashboard := range dashes {
dashboardUIDs = append(dashboardUIDs, dashboard.UID)
}
// Delete all public dashboards in the folders
err = s.publicDashboardService.DeleteByDashboardUIDs(ctx, cmd.OrgID, dashboardUIDs)
if err != nil {
return folder.ErrInternal.Errorf("failed to delete public dashboards: %w", err)
}
}
}
err = s.unifiedStore.Delete(ctx, folders, cmd.OrgID)
@@ -10,6 +10,7 @@ import (
"net/http/httptest"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
clientrest "k8s.io/client-go/rest"
@@ -31,6 +32,7 @@ import (
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/guardian"
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/storage/unified/resource"
@@ -202,18 +204,21 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
featuresArr := []any{
featuremgmt.FlagKubernetesFoldersServiceV2}
features := featuremgmt.WithFeatures(featuresArr...)
dashboardStore := dashboards.NewFakeDashboardStore(t)
publicDashboardService := publicdashboards.NewFakePublicDashboardServiceWrapper(t)
folderService := &Service{
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
unifiedStore: unifiedStore,
features: features,
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
// db: db,
accessControl: acimpl.ProvideAccessControl(features),
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(nil),
tracer: tracing.InitializeTracerForTest(),
k8sclient: k8sHandler,
log: slog.New(logtest.NewTestHandler(t)).With("logger", "test-folder-service"),
unifiedStore: unifiedStore,
features: features,
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
accessControl: acimpl.ProvideAccessControl(features),
registry: make(map[string]folder.RegistryService),
metrics: newFoldersMetrics(nil),
tracer: tracing.InitializeTracerForTest(),
k8sclient: k8sHandler,
dashboardStore: dashboardStore,
publicDashboardService: publicDashboardService,
}
require.NoError(t, folderService.RegisterService(alertingStore))
@@ -345,6 +350,9 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
})
t.Run("When deleting folder by uid should not return access denied error - ForceDeleteRules false", func(t *testing.T) {
dashboardStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{}, nil)
publicDashboardService.On("DeleteByDashboardUIDs", mock.Anything, mock.Anything, mock.Anything).Return(nil)
err := folderService.Delete(ctx, &folder.DeleteFolderCommand{
UID: "deletefolder",
OrgID: orgID,
@@ -305,7 +305,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
fStore := folderimpl.ProvideStore(sqlStore)
folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore,
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
_, err = folderSvc.Create(context.Background(), &folder.CreateFolderCommand{UID: folderUID, SignedInUser: &user, Title: folderUID + "-title"})
require.NoError(t, err)
service, err := dashboardservice.ProvideDashboardServiceImpl(
@@ -319,6 +319,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
nil,
quotaService,
nil,
nil,
)
require.NoError(t, err)
service.RegisterDashboardPermissions(dashboardPermissions)
@@ -341,7 +342,7 @@ func createFolder(t *testing.T, sc scenarioContext, title string, folderSvc fold
folderStore := folderimpl.ProvideDashboardFolderStore(sc.sqlStore)
store := folderimpl.ProvideStore(sc.sqlStore)
folderSvc = folderimpl.ProvideService(store, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, folderStore, sc.sqlStore,
features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
t.Logf("Creating folder with title and UID %q", title)
}
ctx := identity.WithRequester(context.Background(), &sc.user)
@@ -404,12 +405,12 @@ func scenarioWithPanel(t *testing.T, desc string, fn func(t *testing.T, sc scena
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
fStore := folderimpl.ProvideStore(sqlStore)
folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore,
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
dashboardService, svcErr := dashboardservice.ProvideDashboardServiceImpl(
cfg, dashboardStore, folderStore,
features, folderPermissions, ac,
folderSvc, fStore,
nil, nil, nil, nil, quotaService, nil,
nil, nil, nil, nil, quotaService, nil, nil,
)
require.NoError(t, svcErr)
dashboardService.RegisterDashboardPermissions(dashboardPermissions)
@@ -470,12 +471,12 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
fStore := folderimpl.ProvideStore(sqlStore)
folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore,
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
dashService, dashSvcErr := dashboardservice.ProvideDashboardServiceImpl(
cfg, dashboardStore, folderStore,
features, folderPermissions, ac,
folderSvc, fStore,
nil, nil, nil, nil, quotaService, nil,
nil, nil, nil, nil, quotaService, nil, nil,
)
require.NoError(t, dashSvcErr)
dashService.RegisterDashboardPermissions(dashboardPermissions)
@@ -735,7 +735,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash
cfg, dashboardStore, folderStore,
features, acmock.NewMockedPermissionsService(), ac,
foldertest.NewFakeService(), folder.NewFakeStore(),
nil, nil, nil, nil, quotaService, nil,
nil, nil, nil, nil, quotaService, nil, nil,
)
require.NoError(t, err)
service.RegisterDashboardPermissions(dashPermissionService)
@@ -756,7 +756,7 @@ func createFolder(t *testing.T, sc scenarioContext, title string) *folder.Folder
folderStore := folderimpl.ProvideDashboardFolderStore(sc.sqlStore)
fStore := folderimpl.ProvideStore(sc.sqlStore)
s := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, folderStore, sc.sqlStore,
features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
t.Logf("Creating folder with title and UID %q", title)
ctx := identity.WithRequester(context.Background(), sc.user)
@@ -832,7 +832,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
cfg, dashStore, folderStore,
features, acmock.NewMockedPermissionsService(), ac,
folderSvc, folder.NewFakeStore(),
nil, nil, nil, nil, quotaService, nil,
nil, nil, nil, nil, quotaService, nil, nil,
)
require.NoError(t, err)
dashService.RegisterDashboardPermissions(dashPermissionService)
@@ -843,7 +843,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
fStore := folderimpl.ProvideStore(sqlStore)
folderService := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, folderStore, sqlStore,
features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
elementService := libraryelements.ProvideService(cfg, sqlStore, routing.NewRouteRegister(), folderService, features, ac)
service := LibraryPanelService{
@@ -1920,7 +1920,7 @@ func createTestEnv(t *testing.T, testConfig string) testEnvironment {
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
fStore := folderimpl.ProvideStore(sqlStore)
folderService := folderimpl.ProvideService(fStore, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardStore, folderStore, sqlStore,
featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
store := store.DBstore{
Logger: log,
SQLStore: sqlStore,
@@ -1604,7 +1604,7 @@ func TestProvisiongWithFullpath(t *testing.T) {
features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
fStore := folderimpl.ProvideStore(sqlStore)
folderService := folderimpl.ProvideService(fStore, ac, inProcBus, dashboardStore, folderStore, sqlStore,
features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
ruleService := createAlertRuleService(t, folderService)
var orgID int64 = 1
+2 -2
View File
@@ -29,7 +29,7 @@ func SetupFolderService(tb testing.TB, cfg *setting.Cfg, db db.DB, dashboardStor
tb.Helper()
fStore := folderimpl.ProvideStore(db)
return folderimpl.ProvideService(fStore, ac, bus, dashboardStore, folderStore, db,
features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
}
func SetupDashboardService(tb testing.TB, sqlStore db.DB, fs *folderimpl.DashboardFolderStoreImpl, cfg *setting.Cfg) (*dashboardservice.DashboardServiceImpl, dashboards.Store) {
@@ -60,7 +60,7 @@ func SetupDashboardService(tb testing.TB, sqlStore db.DB, fs *folderimpl.Dashboa
cfg, dashboardStore, fs,
features, folderPermissions, ac,
foldertest.NewFakeService(), folder.NewFakeStore(),
nil, nil, nil, nil, quotaService, nil,
nil, nil, nil, nil, quotaService, nil, nil,
)
require.NoError(tb, err)
dashboardService.RegisterDashboardPermissions(dashboardPermissions)
@@ -325,7 +325,7 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T)
dashService, err := service.ProvideDashboardServiceImpl(
cfg, dashboardStoreService, folderStore,
featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), ac,
foldertest.NewFakeService(), folder.NewFakeStore(), nil, nil, nil, nil, quotatest.New(false, nil), nil,
foldertest.NewFakeService(), folder.NewFakeStore(), nil, nil, nil, nil, quotatest.New(false, nil), nil, nil,
)
require.NoError(t, err)
dashService.RegisterDashboardPermissions(dashPermissionService)
@@ -3,6 +3,8 @@ package database
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
@@ -10,7 +12,6 @@ import (
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/publicdashboards"
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
)
@@ -256,7 +257,7 @@ func (d *PublicDashboardStoreImpl) Update(ctx context.Context, cmd SavePublicDas
return affectedRows, err
}
// Deletes a public dashboard
// Delete deletes a public dashboard
func (d *PublicDashboardStoreImpl) Delete(ctx context.Context, uid string) (int64, error) {
dashboard := &PublicDashboard{Uid: uid}
var affectedRows int64
@@ -270,17 +271,28 @@ func (d *PublicDashboardStoreImpl) Delete(ctx context.Context, uid string) (int6
return affectedRows, err
}
func (d *PublicDashboardStoreImpl) FindByFolder(ctx context.Context, orgId int64, folderUid string) ([]*PublicDashboard, error) {
var pubdashes []*PublicDashboard
err := d.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
return sess.SQL("SELECT * from dashboard_public WHERE (dashboard_uid, org_id) IN (SELECT uid, org_id FROM dashboard WHERE org_id = ? AND folder_uid = ?)", orgId, folderUid).Find(&pubdashes)
})
if err != nil {
return nil, err
// DeleteByDashboardUIDs deletes public dashboards by dashboard uids
func (d *PublicDashboardStoreImpl) DeleteByDashboardUIDs(ctx context.Context, orgId int64, dashboardUIDs []string) error {
if len(dashboardUIDs) == 0 {
return nil
}
return pubdashes, nil
return d.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
s := strings.Builder{}
s.WriteString("DELETE FROM dashboard_public WHERE org_id = ? AND ")
s.WriteString(fmt.Sprintf("dashboard_uid IN (%s)", strings.Repeat("?,", len(dashboardUIDs)-1)+"?"))
sql := s.String()
args := make([]any, 0, len(dashboardUIDs)+2)
args = append(args, sql)
args = append(args, orgId)
for _, dashboardUID := range dashboardUIDs {
args = append(args, dashboardUID)
}
_, err := sess.Exec(args...)
return err
})
}
func (d *PublicDashboardStoreImpl) GetMetrics(ctx context.Context) (*Metrics, error) {
@@ -682,48 +682,53 @@ func TestIntegrationDelete(t *testing.T) {
})
}
func TestFindByFolder(t *testing.T) {
t.Run("returns nil when dashboard is not a folder", func(t *testing.T) {
sqlStore, cfg := db.InitTestDBWithCfg(t)
dashboard := &dashboards.Dashboard{OrgID: 1, UID: "dashboarduid", IsFolder: false}
func TestDeleteByDashboardUIDs(t *testing.T) {
var sqlStore db.DB
var cfg *setting.Cfg
var dashboardStore dashboards.Store
var publicdashboardStore *PublicDashboardStoreImpl
var savedDashboard *dashboards.Dashboard
//var savedPublicDashboard *PublicDashboard
var err error
setup := func() {
sqlStore, cfg = db.InitTestDBWithCfg(t)
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore))
require.NoError(t, err)
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, "", true)
_ = insertPublicDashboard(t, publicdashboardStore, savedDashboard.UID, savedDashboard.OrgID, true, PublicShareType)
}
t.Run("returns nil when dashboardUIDs is empty", func(t *testing.T) {
setup()
var dashboardUIDs []string
store := ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
pubdashes, err := store.FindByFolder(context.Background(), dashboard.OrgID, dashboard.UID)
err := store.DeleteByDashboardUIDs(context.Background(), 1, dashboardUIDs)
require.NoError(t, err)
assert.Nil(t, pubdashes)
assert.Nil(t, err)
})
t.Run("returns nil when parameters are empty", func(t *testing.T) {
sqlStore, cfg := db.InitTestDBWithCfg(t)
store := ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
pubdashes, err := store.FindByFolder(context.Background(), 0, "")
t.Run("deletes public dashboards with provided dashboard uids", func(t *testing.T) {
setup()
// confirm the pubdash exists
pubdash, err := publicdashboardStore.FindByDashboardUid(context.Background(), savedDashboard.OrgID, savedDashboard.UID)
require.NoError(t, err)
assert.Nil(t, pubdashes)
})
assert.NotNil(t, pubdash)
t.Run("can get all pubdashes for dashboard folder and org", func(t *testing.T) {
sqlStore, cfg := db.InitTestDBWithCfg(t)
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore))
dashboardUIDs := []string{savedDashboard.UID}
// delete the pubdash by dashboard uid
err = publicdashboardStore.DeleteByDashboardUIDs(context.Background(), 1, dashboardUIDs)
require.NoError(t, err)
pubdashStore := ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
// insert folders
folder := insertTestDashboard(t, dashboardStore, "This is a folder", 1, "", true, PublicShareType)
folder2 := insertTestDashboard(t, dashboardStore, "This is another folder", 1, "", true, PublicShareType)
// insert dashboard in a folder
dashboard := insertTestDashboard(t, dashboardStore, "Dashboard in a folder", 1, folder.UID, false, PublicShareType)
// insert a dashboard in a different folder
dashboard2 := insertTestDashboard(t, dashboardStore, "Another Dashboard in a different folder", 1, folder2.UID, false, PublicShareType)
// create 2 public dashboards
pubdash := insertPublicDashboard(t, pubdashStore, dashboard.UID, dashboard.OrgID, true, PublicShareType)
_ = insertPublicDashboard(t, pubdashStore, dashboard2.UID, dashboard2.OrgID, true, PublicShareType)
pubdashes, err := pubdashStore.FindByFolder(context.Background(), folder.OrgID, folder.UID)
assert.Nil(t, err)
// confirm the pubdash was deleted
pubdash, err = publicdashboardStore.FindByDashboardUid(context.Background(), savedDashboard.OrgID, savedDashboard.UID)
require.NoError(t, err)
assert.Len(t, pubdashes, 1)
assert.Equal(t, pubdash, pubdashes[0])
assert.Nil(t, pubdash)
})
}
@@ -1,4 +1,4 @@
// Code generated by mockery v2.36.1. DO NOT EDIT.
// Code generated by mockery v2.42.2. DO NOT EDIT.
package publicdashboards
@@ -27,6 +27,10 @@ type FakePublicDashboardService struct {
func (_m *FakePublicDashboardService) Create(ctx context.Context, u *user.SignedInUser, dto *models.SavePublicDashboardDTO) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, u, dto)
if len(ret) == 0 {
panic("no return value specified for Create")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, *models.SavePublicDashboardDTO) (*models.PublicDashboard, error)); ok {
@@ -53,6 +57,10 @@ func (_m *FakePublicDashboardService) Create(ctx context.Context, u *user.Signed
func (_m *FakePublicDashboardService) Delete(ctx context.Context, uid string, dashboardUid string) error {
ret := _m.Called(ctx, uid, dashboardUid)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
r0 = rf(ctx, uid, dashboardUid)
@@ -63,24 +71,14 @@ func (_m *FakePublicDashboardService) Delete(ctx context.Context, uid string, da
return r0
}
// DeleteByDashboard provides a mock function with given fields: ctx, dashboard
func (_m *FakePublicDashboardService) DeleteByDashboard(ctx context.Context, dashboard *dashboards.Dashboard) error {
ret := _m.Called(ctx, dashboard)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *dashboards.Dashboard) error); ok {
r0 = rf(ctx, dashboard)
} else {
r0 = ret.Error(0)
}
return r0
}
// ExistsEnabledByAccessToken provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardService) ExistsEnabledByAccessToken(ctx context.Context, accessToken string) (bool, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for ExistsEnabledByAccessToken")
}
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
@@ -105,6 +103,10 @@ func (_m *FakePublicDashboardService) ExistsEnabledByAccessToken(ctx context.Con
func (_m *FakePublicDashboardService) ExistsEnabledByDashboardUid(ctx context.Context, dashboardUid string) (bool, error) {
ret := _m.Called(ctx, dashboardUid)
if len(ret) == 0 {
panic("no return value specified for ExistsEnabledByDashboardUid")
}
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
@@ -129,6 +131,10 @@ func (_m *FakePublicDashboardService) ExistsEnabledByDashboardUid(ctx context.Co
func (_m *FakePublicDashboardService) Find(ctx context.Context, uid string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, uid)
if len(ret) == 0 {
panic("no return value specified for Find")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*models.PublicDashboard, error)); ok {
@@ -155,6 +161,10 @@ func (_m *FakePublicDashboardService) Find(ctx context.Context, uid string) (*mo
func (_m *FakePublicDashboardService) FindAllWithPagination(ctx context.Context, query *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error) {
ret := _m.Called(ctx, query)
if len(ret) == 0 {
panic("no return value specified for FindAllWithPagination")
}
var r0 *models.PublicDashboardListResponseWithPagination
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error)); ok {
@@ -181,6 +191,10 @@ func (_m *FakePublicDashboardService) FindAllWithPagination(ctx context.Context,
func (_m *FakePublicDashboardService) FindAnnotations(ctx context.Context, reqDTO models.AnnotationsQueryDTO, accessToken string) ([]models.AnnotationEvent, error) {
ret := _m.Called(ctx, reqDTO, accessToken)
if len(ret) == 0 {
panic("no return value specified for FindAnnotations")
}
var r0 []models.AnnotationEvent
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, models.AnnotationsQueryDTO, string) ([]models.AnnotationEvent, error)); ok {
@@ -207,6 +221,10 @@ func (_m *FakePublicDashboardService) FindAnnotations(ctx context.Context, reqDT
func (_m *FakePublicDashboardService) FindByAccessToken(ctx context.Context, accessToken string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for FindByAccessToken")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*models.PublicDashboard, error)); ok {
@@ -233,6 +251,10 @@ func (_m *FakePublicDashboardService) FindByAccessToken(ctx context.Context, acc
func (_m *FakePublicDashboardService) FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
if len(ret) == 0 {
panic("no return value specified for FindByDashboardUid")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*models.PublicDashboard, error)); ok {
@@ -259,6 +281,10 @@ func (_m *FakePublicDashboardService) FindByDashboardUid(ctx context.Context, or
func (_m *FakePublicDashboardService) FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
if len(ret) == 0 {
panic("no return value specified for FindDashboard")
}
var r0 *dashboards.Dashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*dashboards.Dashboard, error)); ok {
@@ -285,6 +311,10 @@ func (_m *FakePublicDashboardService) FindDashboard(ctx context.Context, orgId i
func (_m *FakePublicDashboardService) FindEnabledPublicDashboardAndDashboardByAccessToken(ctx context.Context, accessToken string) (*models.PublicDashboard, *dashboards.Dashboard, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for FindEnabledPublicDashboardAndDashboardByAccessToken")
}
var r0 *models.PublicDashboard
var r1 *dashboards.Dashboard
var r2 error
@@ -320,6 +350,10 @@ func (_m *FakePublicDashboardService) FindEnabledPublicDashboardAndDashboardByAc
func (_m *FakePublicDashboardService) FindPublicDashboardAndDashboardByAccessToken(ctx context.Context, accessToken string) (*models.PublicDashboard, *dashboards.Dashboard, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for FindPublicDashboardAndDashboardByAccessToken")
}
var r0 *models.PublicDashboard
var r1 *dashboards.Dashboard
var r2 error
@@ -355,6 +389,10 @@ func (_m *FakePublicDashboardService) FindPublicDashboardAndDashboardByAccessTok
func (_m *FakePublicDashboardService) GetMetricRequest(ctx context.Context, dashboard *dashboards.Dashboard, publicDashboard *models.PublicDashboard, panelId int64, reqDTO models.PublicDashboardQueryDTO) (dtos.MetricRequest, error) {
ret := _m.Called(ctx, dashboard, publicDashboard, panelId, reqDTO)
if len(ret) == 0 {
panic("no return value specified for GetMetricRequest")
}
var r0 dtos.MetricRequest
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *dashboards.Dashboard, *models.PublicDashboard, int64, models.PublicDashboardQueryDTO) (dtos.MetricRequest, error)); ok {
@@ -379,6 +417,10 @@ func (_m *FakePublicDashboardService) GetMetricRequest(ctx context.Context, dash
func (_m *FakePublicDashboardService) GetOrgIdByAccessToken(ctx context.Context, accessToken string) (int64, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for GetOrgIdByAccessToken")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (int64, error)); ok {
@@ -403,6 +445,10 @@ func (_m *FakePublicDashboardService) GetOrgIdByAccessToken(ctx context.Context,
func (_m *FakePublicDashboardService) GetPublicDashboardForView(ctx context.Context, accessToken string) (*dtos.DashboardFullWithMeta, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for GetPublicDashboardForView")
}
var r0 *dtos.DashboardFullWithMeta
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*dtos.DashboardFullWithMeta, error)); ok {
@@ -429,6 +475,10 @@ func (_m *FakePublicDashboardService) GetPublicDashboardForView(ctx context.Cont
func (_m *FakePublicDashboardService) GetQueryDataResponse(ctx context.Context, skipDSCache bool, reqDTO models.PublicDashboardQueryDTO, panelId int64, accessToken string) (*backend.QueryDataResponse, error) {
ret := _m.Called(ctx, skipDSCache, reqDTO, panelId, accessToken)
if len(ret) == 0 {
panic("no return value specified for GetQueryDataResponse")
}
var r0 *backend.QueryDataResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, bool, models.PublicDashboardQueryDTO, int64, string) (*backend.QueryDataResponse, error)); ok {
@@ -455,6 +505,10 @@ func (_m *FakePublicDashboardService) GetQueryDataResponse(ctx context.Context,
func (_m *FakePublicDashboardService) NewPublicDashboardAccessToken(ctx context.Context) (string, error) {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for NewPublicDashboardAccessToken")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok {
@@ -479,6 +533,10 @@ func (_m *FakePublicDashboardService) NewPublicDashboardAccessToken(ctx context.
func (_m *FakePublicDashboardService) NewPublicDashboardUid(ctx context.Context) (string, error) {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for NewPublicDashboardUid")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok {
@@ -503,6 +561,10 @@ func (_m *FakePublicDashboardService) NewPublicDashboardUid(ctx context.Context)
func (_m *FakePublicDashboardService) Update(ctx context.Context, u *user.SignedInUser, dto *models.SavePublicDashboardDTO) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, u, dto)
if len(ret) == 0 {
panic("no return value specified for Update")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, *models.SavePublicDashboardDTO) (*models.PublicDashboard, error)); ok {
@@ -1,4 +1,4 @@
// Code generated by mockery v2.36.1. DO NOT EDIT.
// Code generated by mockery v2.42.2. DO NOT EDIT.
package publicdashboards
@@ -18,6 +18,10 @@ type FakePublicDashboardServiceWrapper struct {
func (_m *FakePublicDashboardServiceWrapper) Delete(ctx context.Context, uid string) error {
ret := _m.Called(ctx, uid)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, uid)
@@ -28,10 +32,32 @@ func (_m *FakePublicDashboardServiceWrapper) Delete(ctx context.Context, uid str
return r0
}
// DeleteByDashboardUIDs provides a mock function with given fields: ctx, orgId, dashboardUIDs
func (_m *FakePublicDashboardServiceWrapper) DeleteByDashboardUIDs(ctx context.Context, orgId int64, dashboardUIDs []string) error {
ret := _m.Called(ctx, orgId, dashboardUIDs)
if len(ret) == 0 {
panic("no return value specified for DeleteByDashboardUIDs")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64, []string) error); ok {
r0 = rf(ctx, orgId, dashboardUIDs)
} else {
r0 = ret.Error(0)
}
return r0
}
// FindByDashboardUid provides a mock function with given fields: ctx, orgId, dashboardUid
func (_m *FakePublicDashboardServiceWrapper) FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
if len(ret) == 0 {
panic("no return value specified for FindByDashboardUid")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*models.PublicDashboard, error)); ok {
@@ -1,4 +1,4 @@
// Code generated by mockery v2.36.1. DO NOT EDIT.
// Code generated by mockery v2.42.2. DO NOT EDIT.
package publicdashboards
@@ -18,6 +18,10 @@ type FakePublicDashboardStore struct {
func (_m *FakePublicDashboardStore) Create(ctx context.Context, cmd models.SavePublicDashboardCommand) (int64, error) {
ret := _m.Called(ctx, cmd)
if len(ret) == 0 {
panic("no return value specified for Create")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, models.SavePublicDashboardCommand) (int64, error)); ok {
@@ -42,6 +46,10 @@ func (_m *FakePublicDashboardStore) Create(ctx context.Context, cmd models.SaveP
func (_m *FakePublicDashboardStore) Delete(ctx context.Context, uid string) (int64, error) {
ret := _m.Called(ctx, uid)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (int64, error)); ok {
@@ -62,10 +70,32 @@ func (_m *FakePublicDashboardStore) Delete(ctx context.Context, uid string) (int
return r0, r1
}
// DeleteByDashboardUIDs provides a mock function with given fields: ctx, orgId, dashboardUIDs
func (_m *FakePublicDashboardStore) DeleteByDashboardUIDs(ctx context.Context, orgId int64, dashboardUIDs []string) error {
ret := _m.Called(ctx, orgId, dashboardUIDs)
if len(ret) == 0 {
panic("no return value specified for DeleteByDashboardUIDs")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64, []string) error); ok {
r0 = rf(ctx, orgId, dashboardUIDs)
} else {
r0 = ret.Error(0)
}
return r0
}
// ExistsEnabledByAccessToken provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardStore) ExistsEnabledByAccessToken(ctx context.Context, accessToken string) (bool, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for ExistsEnabledByAccessToken")
}
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
@@ -90,6 +120,10 @@ func (_m *FakePublicDashboardStore) ExistsEnabledByAccessToken(ctx context.Conte
func (_m *FakePublicDashboardStore) ExistsEnabledByDashboardUid(ctx context.Context, dashboardUid string) (bool, error) {
ret := _m.Called(ctx, dashboardUid)
if len(ret) == 0 {
panic("no return value specified for ExistsEnabledByDashboardUid")
}
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
@@ -114,6 +148,10 @@ func (_m *FakePublicDashboardStore) ExistsEnabledByDashboardUid(ctx context.Cont
func (_m *FakePublicDashboardStore) Find(ctx context.Context, uid string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, uid)
if len(ret) == 0 {
panic("no return value specified for Find")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*models.PublicDashboard, error)); ok {
@@ -140,6 +178,10 @@ func (_m *FakePublicDashboardStore) Find(ctx context.Context, uid string) (*mode
func (_m *FakePublicDashboardStore) FindAll(ctx context.Context, query *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error) {
ret := _m.Called(ctx, query)
if len(ret) == 0 {
panic("no return value specified for FindAll")
}
var r0 *models.PublicDashboardListResponseWithPagination
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error)); ok {
@@ -166,6 +208,10 @@ func (_m *FakePublicDashboardStore) FindAll(ctx context.Context, query *models.P
func (_m *FakePublicDashboardStore) FindByAccessToken(ctx context.Context, accessToken string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for FindByAccessToken")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*models.PublicDashboard, error)); ok {
@@ -192,6 +238,10 @@ func (_m *FakePublicDashboardStore) FindByAccessToken(ctx context.Context, acces
func (_m *FakePublicDashboardStore) FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
if len(ret) == 0 {
panic("no return value specified for FindByDashboardUid")
}
var r0 *models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*models.PublicDashboard, error)); ok {
@@ -218,6 +268,10 @@ func (_m *FakePublicDashboardStore) FindByDashboardUid(ctx context.Context, orgI
func (_m *FakePublicDashboardStore) FindByFolder(ctx context.Context, orgId int64, folderUid string) ([]*models.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, folderUid)
if len(ret) == 0 {
panic("no return value specified for FindByFolder")
}
var r0 []*models.PublicDashboard
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, string) ([]*models.PublicDashboard, error)); ok {
@@ -244,6 +298,10 @@ func (_m *FakePublicDashboardStore) FindByFolder(ctx context.Context, orgId int6
func (_m *FakePublicDashboardStore) GetMetrics(ctx context.Context) (*models.Metrics, error) {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for GetMetrics")
}
var r0 *models.Metrics
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) (*models.Metrics, error)); ok {
@@ -270,6 +328,10 @@ func (_m *FakePublicDashboardStore) GetMetrics(ctx context.Context) (*models.Met
func (_m *FakePublicDashboardStore) GetOrgIdByAccessToken(ctx context.Context, accessToken string) (int64, error) {
ret := _m.Called(ctx, accessToken)
if len(ret) == 0 {
panic("no return value specified for GetOrgIdByAccessToken")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (int64, error)); ok {
@@ -294,6 +356,10 @@ func (_m *FakePublicDashboardStore) GetOrgIdByAccessToken(ctx context.Context, a
func (_m *FakePublicDashboardStore) Update(ctx context.Context, cmd models.SavePublicDashboardCommand) (int64, error) {
ret := _m.Called(ctx, cmd)
if len(ret) == 0 {
panic("no return value specified for Update")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, models.SavePublicDashboardCommand) (int64, error)); ok {
@@ -28,7 +28,6 @@ type Service interface {
Create(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
Update(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
Delete(ctx context.Context, uid string, dashboardUid string) error
DeleteByDashboard(ctx context.Context, dashboard *dashboards.Dashboard) error
GetMetricRequest(ctx context.Context, dashboard *dashboards.Dashboard, publicDashboard *PublicDashboard, panelId int64, reqDTO PublicDashboardQueryDTO) (dtos.MetricRequest, error)
GetQueryDataResponse(ctx context.Context, skipDSCache bool, reqDTO PublicDashboardQueryDTO, panelId int64, accessToken string) (*backend.QueryDataResponse, error)
@@ -46,6 +45,7 @@ type Service interface {
type ServiceWrapper interface {
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
Delete(ctx context.Context, uid string) error
DeleteByDashboardUIDs(ctx context.Context, orgId int64, dashboardUIDs []string) error
}
//go:generate mockery --name Store --structname FakePublicDashboardStore --inpackage --filename public_dashboard_store_mock.go
@@ -57,9 +57,9 @@ type Store interface {
Create(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
Update(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
Delete(ctx context.Context, uid string) (int64, error)
DeleteByDashboardUIDs(ctx context.Context, orgId int64, dashboardUIDs []string) error
GetOrgIdByAccessToken(ctx context.Context, accessToken string) (int64, error)
FindByFolder(ctx context.Context, orgId int64, folderUid string) ([]*PublicDashboard, error)
ExistsEnabledByAccessToken(ctx context.Context, accessToken string) (bool, error)
ExistsEnabledByDashboardUid(ctx context.Context, dashboardUid string) (bool, error)
GetMetrics(ctx context.Context) (*Metrics, error)
@@ -459,37 +459,6 @@ func (pd *PublicDashboardServiceImpl) Delete(ctx context.Context, uid string, da
return pd.serviceWrapper.Delete(ctx, uid)
}
func (pd *PublicDashboardServiceImpl) DeleteByDashboard(ctx context.Context, dashboard *dashboards.Dashboard) error {
ctx, span := tracer.Start(ctx, "publicdashboards.DeleteByDashboard")
defer span.End()
if dashboard.IsFolder {
// get all pubdashes for the folder
pubdashes, err := pd.store.FindByFolder(ctx, dashboard.OrgID, dashboard.UID)
if err != nil {
return err
}
// delete each pubdash
for _, pubdash := range pubdashes {
err = pd.serviceWrapper.Delete(ctx, pubdash.Uid)
if err != nil {
return err
}
}
return nil
}
pubdash, err := pd.store.FindByDashboardUid(ctx, dashboard.OrgID, dashboard.UID)
if err != nil {
return ErrInternalServerError.Errorf("DeleteByDashboard: error finding a public dashboard by dashboard orgId: %d and Uid: %s %w", dashboard.OrgID, dashboard.UID, err)
}
if pubdash == nil {
return nil
}
return pd.serviceWrapper.Delete(ctx, pubdash.Uid)
}
// intervalMS and maxQueryData values are being calculated on the frontend for regular dashboards
// we are doing the same for public dashboards but because this access would be public, we need a way to keep this
// values inside reasonable bounds to avoid an attack that could hit data sources with a small interval and a big
@@ -1394,9 +1394,9 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
fStore := folderimpl.ProvideStore(testDB)
folderPermissions := acmock.NewMockedPermissionsService()
folderStore := folderimpl.ProvideDashboardFolderStore(testDB)
folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, folderStore, testDB, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderSvc := folderimpl.ProvideService(fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, folderStore, testDB, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
dashboardService, err := dashsvc.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), folderPermissions, ac, folderSvc, fStore, nil, nil, nil, nil, quotatest.New(false, nil), nil)
dashboardService, err := dashsvc.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), folderPermissions, ac, folderSvc, fStore, nil, nil, nil, nil, quotatest.New(false, nil), nil, nil)
require.NoError(t, err)
dashboardService.RegisterDashboardPermissions(&actest.FakePermissionsService{})
fakeGuardian := &guardian.FakeDashboardGuardian{
@@ -2053,42 +2053,6 @@ func TestPublicDashboardServiceImpl_NewPublicDashboardAccessToken(t *testing.T)
}
}
func TestDeleteByDashboard(t *testing.T) {
t.Run("will return nil when pubdash not found", func(t *testing.T) {
store := NewFakePublicDashboardStore(t)
pd := &PublicDashboardServiceImpl{store: store, serviceWrapper: ProvideServiceWrapper(store)}
dashboard := &dashboards.Dashboard{UID: "1", OrgID: 1, IsFolder: false}
store.On("FindByDashboardUid", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
err := pd.DeleteByDashboard(context.Background(), dashboard)
assert.Nil(t, err)
})
t.Run("will delete pubdash when dashboard deleted", func(t *testing.T) {
store := NewFakePublicDashboardStore(t)
pd := &PublicDashboardServiceImpl{store: store, serviceWrapper: ProvideServiceWrapper(store)}
dashboard := &dashboards.Dashboard{UID: "1", OrgID: 1, IsFolder: false}
pubdash := &PublicDashboard{Uid: "2", OrgId: 1, DashboardUid: dashboard.UID}
store.On("FindByDashboardUid", mock.Anything, mock.Anything, mock.Anything).Return(pubdash, nil)
store.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil)
err := pd.DeleteByDashboard(context.Background(), dashboard)
require.NoError(t, err)
})
t.Run("will delete pubdashes when dashboard folder deleted", func(t *testing.T) {
store := NewFakePublicDashboardStore(t)
pd := &PublicDashboardServiceImpl{store: store, serviceWrapper: ProvideServiceWrapper(store)}
dashboard := &dashboards.Dashboard{UID: "1", OrgID: 1, IsFolder: true}
pubdash1 := &PublicDashboard{Uid: "2", OrgId: 1, DashboardUid: dashboard.UID}
pubdash2 := &PublicDashboard{Uid: "3", OrgId: 1, DashboardUid: dashboard.UID}
store.On("FindByFolder", mock.Anything, mock.Anything, mock.Anything).Return([]*PublicDashboard{pubdash1, pubdash2}, nil)
store.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil)
err := pd.DeleteByDashboard(context.Background(), dashboard)
require.NoError(t, err)
})
}
func TestGenerateAccessToken(t *testing.T) {
accessToken, err := GenerateAccessToken()
@@ -52,3 +52,12 @@ func (pd *PublicDashboardServiceWrapperImpl) Delete(ctx context.Context, uid str
return nil
}
func (pd *PublicDashboardServiceWrapperImpl) DeleteByDashboardUIDs(ctx context.Context, orgId int64, dashboardUIDs []string) error {
err := pd.store.DeleteByDashboardUIDs(ctx, orgId, dashboardUIDs)
if err != nil {
return ErrInternalServerError.Errorf("DeleteByDashboardUIDs: failed to delete public dashboards by dashboard UIDs: %v %w", dashboardUIDs, err)
}
return nil
}
+2 -2
View File
@@ -493,9 +493,9 @@ func setupEnv(t *testing.T, sqlStore db.DB, cfg *setting.Cfg, b bus.Bus, quotaSe
ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures())
folderSvc := folderimpl.ProvideService(fStore, acmock.New(), bus.ProvideBus(tracing.InitializeTracerForTest()),
dashStore, folderStore, sqlStore, featuremgmt.WithFeatures(),
supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
dashService, err := dashService.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(),
ac, folderSvc, fStore, nil, nil, nil, nil, quotaService, nil)
ac, folderSvc, fStore, nil, nil, nil, nil, quotaService, nil, nil)
require.NoError(t, err)
dashService.RegisterDashboardPermissions(acmock.NewMockedPermissionsService())
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
@@ -823,7 +823,7 @@ func setupNestedTest(t *testing.T, usr *user.SignedInUser, perms []accesscontrol
fStore := folderimpl.ProvideStore(db)
folderSvc := folderimpl.ProvideService(fStore, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore,
folderimpl.ProvideDashboardFolderStore(db), db, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
folderimpl.ProvideDashboardFolderStore(db), db, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
// create parent folder
parent, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{
@@ -80,7 +80,7 @@ func setupBenchMark(b *testing.B, usr user.SignedInUser, features featuremgmt.Fe
fStore := folderimpl.ProvideStore(store)
folderSvc := folderimpl.ProvideService(fStore, mock.New(), bus.ProvideBus(tracing.InitializeTracerForTest()), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(store),
store, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
store, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
origNewGuardian := guardian.New
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true, CanSaveValue: true})
@@ -52,7 +52,7 @@ func TestDirectSQLStats(t *testing.T) {
fStore := folderimpl.ProvideStore(db)
folderSvc := folderimpl.ProvideService(fStore, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore,
folderimpl.ProvideDashboardFolderStore(db), db, featuremgmt.WithFeatures(),
supportbundlestest.NewFakeBundleService(), cfg, nil, tracing.InitializeTracerForTest())
supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest())
// create parent folder