Chore: Remove bus from dashboard service (#46829)

* Move DeleteDashboard funtion into dashboards store service, remove bus and update tests

* Remove bus from folder service and update more tests

* Fix mock
This commit is contained in:
Selene 2022-03-22 14:36:50 +01:00 committed by GitHub
parent bfb03d779d
commit b2af18f129
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 183 additions and 202 deletions

View File

@ -47,12 +47,6 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
})
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
getDashboardQueryResult := models.NewDashboard("Dash")
mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = getDashboardQueryResult
mockSQLStore.ExpectedError = nil
hs.SQLStore = mockSQLStore
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
callGetDashboardPermissions(sc, hs)
@ -96,10 +90,6 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
},
})
mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = models.NewDashboard("Dash")
hs.SQLStore = mockSQLStore
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
callGetDashboardPermissions(sc, hs)

View File

@ -51,6 +51,7 @@ type Store interface {
UnprovisionDashboard(ctx context.Context, id int64) error
// GetDashboardsByPluginID retrieves dashboards identified by plugin.
GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error
DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error
FolderStore
}

View File

@ -4,11 +4,14 @@ import (
"context"
"errors"
"fmt"
"strconv"
"time"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/util"
@ -223,7 +226,7 @@ func (d *DashboardStore) SaveAlerts(ctx context.Context, dashID int64, alerts []
return err
}
if err := deleteMissingAlerts(existingAlerts, alerts, sess, d.log); err != nil {
if err := d.deleteMissingAlerts(existingAlerts, alerts, sess); err != nil {
return err
}
@ -255,7 +258,7 @@ func (d *DashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context
}
for _, deleteDashCommand := range result {
err := d.sqlStore.DeleteDashboard(ctx, &models.DeleteDashboardCommand{Id: deleteDashCommand.DashboardId})
err := d.DeleteDashboard(ctx, &models.DeleteDashboardCommand{Id: deleteDashCommand.DashboardId})
if err != nil && !errors.Is(err, models.ErrDashboardNotFound) {
return err
}
@ -613,7 +616,7 @@ func updateAlerts(existingAlerts []*models.Alert, alerts []*models.Alert, sess *
return nil
}
func deleteMissingAlerts(alerts []*models.Alert, existingAlerts []*models.Alert, sess *sqlstore.DBSession, log log.Logger) error {
func (d *DashboardStore) deleteMissingAlerts(alerts []*models.Alert, existingAlerts []*models.Alert, sess *sqlstore.DBSession) error {
for _, missingAlert := range alerts {
missing := true
@ -625,7 +628,7 @@ func deleteMissingAlerts(alerts []*models.Alert, existingAlerts []*models.Alert,
}
if missing {
if err := deleteAlertByIdInternal(missingAlert.Id, "Removed from dashboard", sess, log); err != nil {
if err := d.deleteAlertByIdInternal(missingAlert.Id, "Removed from dashboard", sess); err != nil {
// No use trying to delete more, since we're in a transaction and it will be
// rolled back on error.
return err
@ -636,8 +639,8 @@ func deleteMissingAlerts(alerts []*models.Alert, existingAlerts []*models.Alert,
return nil
}
func deleteAlertByIdInternal(alertId int64, reason string, sess *sqlstore.DBSession, log log.Logger) error {
log.Debug("Deleting alert", "id", alertId, "reason", reason)
func (d *DashboardStore) deleteAlertByIdInternal(alertId int64, reason string, sess *sqlstore.DBSession) error {
d.log.Debug("Deleting alert", "id", alertId, "reason", reason)
if _, err := sess.Exec("DELETE FROM alert WHERE id = ?", alertId); err != nil {
return err
@ -690,3 +693,138 @@ func (d *DashboardStore) GetDashboardsByPluginID(ctx context.Context, query *mod
return err
})
}
func (d *DashboardStore) DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error {
return d.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
return d.deleteDashboard(cmd, sess)
})
}
func (d *DashboardStore) deleteDashboard(cmd *models.DeleteDashboardCommand, sess *sqlstore.DBSession) error {
dashboard := models.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
has, err := sess.Get(&dashboard)
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
}
deletes := []string{
"DELETE FROM dashboard_tag WHERE dashboard_id = ? ",
"DELETE FROM star WHERE dashboard_id = ? ",
"DELETE FROM dashboard WHERE id = ?",
"DELETE FROM playlist_item WHERE type = 'dashboard_by_id' AND value = ?",
"DELETE FROM dashboard_version WHERE dashboard_id = ?",
"DELETE FROM annotation WHERE dashboard_id = ?",
"DELETE FROM dashboard_provisioning WHERE dashboard_id = ?",
"DELETE FROM dashboard_acl WHERE dashboard_id = ?",
}
if dashboard.IsFolder {
deletes = append(deletes, "DELETE FROM dashboard WHERE folder_id = ?")
var dashIds []struct {
Id int64
}
err := sess.SQL("SELECT id FROM dashboard WHERE folder_id = ?", dashboard.Id).Find(&dashIds)
if err != nil {
return err
}
for _, id := range dashIds {
if err := d.deleteAlertDefinition(id.Id, sess); err != nil {
return err
}
}
// remove all access control permission with folder scope
_, err = sess.Exec("DELETE FROM permission WHERE scope = ?", dashboards.ScopeFoldersProvider.GetResourceScope(strconv.FormatInt(dashboard.Id, 10)))
if err != nil {
return err
}
for _, dash := range dashIds {
// remove all access control permission with child dashboard scopes
_, err = sess.Exec("DELETE FROM permission WHERE scope = ?", ac.Scope("dashboards", "id", strconv.FormatInt(dash.Id, 10)))
if err != nil {
return err
}
}
if len(dashIds) > 0 {
childrenDeletes := []string{
"DELETE FROM dashboard_tag WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM star WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM dashboard_version WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM annotation WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM dashboard_provisioning WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM dashboard_acl WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
}
for _, sql := range childrenDeletes {
_, err := sess.Exec(sql, dashboard.OrgId, dashboard.Id)
if err != nil {
return err
}
}
}
var existingRuleID int64
exists, err := sess.Table("alert_rule").Where("namespace_uid = (SELECT uid FROM dashboard WHERE id = ?)", dashboard.Id).Cols("id").Get(&existingRuleID)
if err != nil {
return err
}
if exists {
if !cmd.ForceDeleteFolderRules {
return fmt.Errorf("folder cannot be deleted: %w", models.ErrFolderContainsAlertRules)
}
// Delete all rules under this folder.
deleteNGAlertsByFolder := []string{
"DELETE FROM alert_rule WHERE namespace_uid = (SELECT uid FROM dashboard WHERE id = ?)",
"DELETE FROM alert_rule_version WHERE rule_namespace_uid = (SELECT uid FROM dashboard WHERE id = ?)",
}
for _, sql := range deleteNGAlertsByFolder {
_, err := sess.Exec(sql, dashboard.Id)
if err != nil {
return err
}
}
}
} else {
_, err = sess.Exec("DELETE FROM permission WHERE scope = ?", ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.Id, 10)))
if err != nil {
return err
}
}
if err := d.deleteAlertDefinition(dashboard.Id, sess); err != nil {
return err
}
for _, sql := range deletes {
_, err := sess.Exec(sql, dashboard.Id)
if err != nil {
return err
}
}
return nil
}
func (d *DashboardStore) deleteAlertDefinition(dashboardId int64, sess *sqlstore.DBSession) error {
alerts := make([]*models.Alert, 0)
if err := sess.Where("dashboard_id = ?", dashboardId).Find(&alerts); err != nil {
return err
}
for _, alert := range alerts {
if err := d.deleteAlertByIdInternal(alert.Id, "Dashboard deleted", sess); err != nil {
// If we return an error, the current transaction gets rolled back, so no use
// trying to delete more
return err
}
}
return nil
}

View File

@ -118,7 +118,7 @@ func TestDashboardDataAccess(t *testing.T) {
setup()
dash := insertTestDashboard(t, dashboardStore, "delete me", 1, 0, false, "delete this")
err := sqlStore.DeleteDashboard(context.Background(), &models.DeleteDashboardCommand{
err := dashboardStore.DeleteDashboard(context.Background(), &models.DeleteDashboardCommand{
Id: dash.Id,
OrgId: 1,
})
@ -193,21 +193,21 @@ func TestDashboardDataAccess(t *testing.T) {
emptyFolder := insertTestDashboard(t, dashboardStore, "2 test dash folder", 1, 0, true, "prod", "webapp")
deleteCmd := &models.DeleteDashboardCommand{Id: emptyFolder.Id}
err := sqlStore.DeleteDashboard(context.Background(), deleteCmd)
err := dashboardStore.DeleteDashboard(context.Background(), deleteCmd)
require.NoError(t, err)
})
t.Run("Should be not able to delete a dashboard if force delete rules is disabled", func(t *testing.T) {
setup()
deleteCmd := &models.DeleteDashboardCommand{Id: savedFolder.Id, ForceDeleteFolderRules: false}
err := sqlStore.DeleteDashboard(context.Background(), deleteCmd)
err := dashboardStore.DeleteDashboard(context.Background(), deleteCmd)
require.True(t, errors.Is(err, models.ErrFolderContainsAlertRules))
})
t.Run("Should be able to delete a dashboard folder and its children if force delete rules is enabled", func(t *testing.T) {
setup()
deleteCmd := &models.DeleteDashboardCommand{Id: savedFolder.Id, ForceDeleteFolderRules: true}
err := sqlStore.DeleteDashboard(context.Background(), deleteCmd)
err := dashboardStore.DeleteDashboard(context.Background(), deleteCmd)
require.NoError(t, err)
query := models.FindPersistedDashboardsQuery{

View File

@ -120,7 +120,7 @@ func TestDashboardProvisioningTest(t *testing.T) {
OrgId: 1,
}
require.Nil(t, sqlStore.DeleteDashboard(context.Background(), deleteCmd))
require.Nil(t, dashboardStore.DeleteDashboard(context.Background(), deleteCmd))
data, err := dashboardStore.GetProvisionedDataByDashboardID(dash.Id)
require.Nil(t, err)

View File

@ -14,6 +14,20 @@ type FakeDashboardStore struct {
mock.Mock
}
// DeleteDashboard provides a mock function with given fields: ctx, cmd
func (_m *FakeDashboardStore) DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error {
ret := _m.Called(ctx, cmd)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *models.DeleteDashboardCommand) error); ok {
r0 = rf(ctx, cmd)
} else {
r0 = ret.Error(0)
}
return r0
}
// DeleteOrphanedProvisionedDashboards provides a mock function with given fields: ctx, cmd
func (_m *FakeDashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *models.DeleteOrphanedProvisionedDashboardsCommand) error {
ret := _m.Called(ctx, cmd)

View File

@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
@ -408,7 +407,7 @@ func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId
}
}
cmd := &models.DeleteDashboardCommand{OrgId: orgId, Id: dashboardId}
return bus.Dispatch(ctx, cmd)
return dr.dashboardStore.DeleteDashboard(ctx, cmd)
}
func (dr *DashboardServiceImpl) ImportDashboard(ctx context.Context, dto *m.SaveDashboardDTO) (

View File

@ -176,35 +176,34 @@ func TestDashboardService(t *testing.T) {
t.Run("Given provisioned dashboard", func(t *testing.T) {
t.Run("DeleteProvisionedDashboard should delete it", func(t *testing.T) {
result := setupDeleteHandlers(t)
args := &models.DeleteDashboardCommand{OrgId: 1, Id: 1}
fakeStore.On("DeleteDashboard", mock.Anything, args).Return(nil).Once()
err := service.DeleteProvisionedDashboard(context.Background(), 1, 1)
require.NoError(t, err)
require.True(t, result.deleteWasCalled)
})
t.Run("DeleteDashboard should fail to delete it", func(t *testing.T) {
t.Run("DeleteDashboard should fail to delete it when provisioning information is missing", func(t *testing.T) {
fakeStore.On("GetProvisionedDataByDashboardID", mock.Anything).Return(&models.DashboardProvisioning{}, nil).Once()
result := setupDeleteHandlers(t)
err := service.DeleteDashboard(context.Background(), 1, 1)
require.Equal(t, err, models.ErrDashboardCannotDeleteProvisionedDashboard)
require.False(t, result.deleteWasCalled)
})
})
t.Run("Given non provisioned dashboard", func(t *testing.T) {
result := setupDeleteHandlers(t)
t.Run("DeleteProvisionedDashboard should delete it", func(t *testing.T) {
t.Run("DeleteProvisionedDashboard should delete the dashboard", func(t *testing.T) {
args := &models.DeleteDashboardCommand{OrgId: 1, Id: 1, ForceDeleteFolderRules: false}
fakeStore.On("DeleteDashboard", mock.Anything, args).Return(nil).Once()
err := service.DeleteProvisionedDashboard(context.Background(), 1, 1)
require.NoError(t, err)
require.True(t, result.deleteWasCalled)
})
t.Run("DeleteDashboard should delete it", func(t *testing.T) {
args := &models.DeleteDashboardCommand{OrgId: 1, Id: 1}
fakeStore.On("DeleteDashboard", mock.Anything, args).Return(nil).Once()
fakeStore.On("GetProvisionedDataByDashboardID", mock.Anything).Return(nil, nil).Once()
err := service.DeleteDashboard(context.Background(), 1, 1)
require.NoError(t, err)
require.True(t, result.deleteWasCalled)
})
})
})
@ -213,17 +212,3 @@ func TestDashboardService(t *testing.T) {
type Result struct {
deleteWasCalled bool
}
func setupDeleteHandlers(t *testing.T) *Result {
t.Helper()
result := &Result{}
bus.AddHandler("test", func(ctx context.Context, cmd *models.DeleteDashboardCommand) error {
require.Equal(t, cmd.Id, int64(1))
require.Equal(t, cmd.OrgId, int64(1))
result.deleteWasCalled = true
return nil
})
return result
}

View File

@ -233,7 +233,8 @@ func (f *FolderServiceImpl) DeleteFolder(ctx context.Context, user *models.Signe
}
deleteCmd := models.DeleteDashboardCommand{OrgId: orgID, Id: dashFolder.Id, ForceDeleteFolderRules: forceDeleteRules}
if err := bus.Dispatch(ctx, &deleteCmd); err != nil {
if err := f.dashboardStore.DeleteDashboard(ctx, &deleteCmd); err != nil {
return nil, toFolderError(err)
}

View File

@ -184,12 +184,11 @@ func TestFolderService(t *testing.T) {
f.Id = rand.Int63()
f.Uid = util.GenerateShortUID()
store.On("GetFolderByUID", mock.Anything, orgID, f.Uid).Return(f, nil)
var actualCmd *models.DeleteDashboardCommand
bus.AddHandler("test", func(ctx context.Context, cmd *models.DeleteDashboardCommand) error {
actualCmd = cmd
return nil
})
defer bus.ClearBusHandlers()
store.On("DeleteDashboard", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
actualCmd = args.Get(1).(*models.DeleteDashboardCommand)
}).Return(nil).Once()
expectedForceDeleteRules := rand.Int63()%2 == 0
_, err := service.DeleteFolder(context.Background(), user, orgID, f.Uid, expectedForceDeleteRules)

View File

@ -155,23 +155,6 @@ func (ss *SQLStore) HandleAlertsQuery(ctx context.Context, query *models.GetAler
})
}
func deleteAlertDefinition(dashboardId int64, sess *DBSession) error {
alerts := make([]*models.Alert, 0)
if err := sess.Where("dashboard_id = ?", dashboardId).Find(&alerts); err != nil {
return err
}
for _, alert := range alerts {
if err := deleteAlertByIdInternal(alert.Id, "Dashboard deleted", sess); err != nil {
// If we return an error, the current transaction gets rolled back, so no use
// trying to delete more
return err
}
}
return nil
}
func (ss *SQLStore) SaveAlerts(ctx context.Context, dashID int64, alerts []*models.Alert) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
existingAlerts, err := GetAlertsByDashboardId2(dashID, sess)

View File

@ -245,9 +245,10 @@ func TestAlertingDataAccess(t *testing.T) {
err := sqlStore.SaveAlerts(context.Background(), testDash.Id, items)
require.Nil(t, err)
err = sqlStore.DeleteDashboard(context.Background(), &models.DeleteDashboardCommand{
OrgId: 1,
Id: testDash.Id,
err = sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
dash := models.Dashboard{Id: testDash.Id, OrgId: 1}
_, err := sess.Delete(dash)
return err
})
require.Nil(t, err)

View File

@ -2,16 +2,12 @@ package sqlstore
import (
"context"
"fmt"
"strconv"
"strings"
"github.com/prometheus/client_golang/prometheus"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
@ -35,7 +31,6 @@ func (ss *SQLStore) addDashboardQueryAndCommandHandlers() {
bus.AddHandler("sql", ss.GetDashboardUIDById)
bus.AddHandler("sql", ss.GetDashboardTags)
bus.AddHandler("sql", ss.SearchDashboards)
bus.AddHandler("sql", ss.DeleteDashboard)
bus.AddHandler("sql", ss.GetDashboards)
bus.AddHandler("sql", ss.HasEditPermissionInFolders)
bus.AddHandler("sql", ss.GetDashboardPermissionsForUser)
@ -239,124 +234,6 @@ func (ss *SQLStore) GetDashboardTags(ctx context.Context, query *models.GetDashb
})
}
func (ss *SQLStore) DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
return deleteDashboard(cmd, sess)
})
}
func deleteDashboard(cmd *models.DeleteDashboardCommand, sess *DBSession) error {
dashboard := models.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
has, err := sess.Get(&dashboard)
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
}
deletes := []string{
"DELETE FROM dashboard_tag WHERE dashboard_id = ? ",
"DELETE FROM star WHERE dashboard_id = ? ",
"DELETE FROM dashboard WHERE id = ?",
"DELETE FROM playlist_item WHERE type = 'dashboard_by_id' AND value = ?",
"DELETE FROM dashboard_version WHERE dashboard_id = ?",
"DELETE FROM annotation WHERE dashboard_id = ?",
"DELETE FROM dashboard_provisioning WHERE dashboard_id = ?",
"DELETE FROM dashboard_acl WHERE dashboard_id = ?",
}
if dashboard.IsFolder {
deletes = append(deletes, "DELETE FROM dashboard WHERE folder_id = ?")
dashIds := []struct {
Id int64
}{}
err := sess.SQL("SELECT id FROM dashboard WHERE folder_id = ?", dashboard.Id).Find(&dashIds)
if err != nil {
return err
}
for _, id := range dashIds {
if err := deleteAlertDefinition(id.Id, sess); err != nil {
return err
}
}
// remove all access control permission with folder scope
_, err = sess.Exec("DELETE FROM permission WHERE scope = ?", dashboards.ScopeFoldersProvider.GetResourceScope(strconv.FormatInt(dashboard.Id, 10)))
if err != nil {
return err
}
for _, dash := range dashIds {
// remove all access control permission with child dashboard scopes
_, err = sess.Exec("DELETE FROM permission WHERE scope = ?", ac.Scope("dashboards", "id", strconv.FormatInt(dash.Id, 10)))
if err != nil {
return err
}
}
if len(dashIds) > 0 {
childrenDeletes := []string{
"DELETE FROM dashboard_tag WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM star WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM dashboard_version WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM annotation WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM dashboard_provisioning WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
"DELETE FROM dashboard_acl WHERE dashboard_id IN (SELECT id FROM dashboard WHERE org_id = ? AND folder_id = ?)",
}
for _, sql := range childrenDeletes {
_, err := sess.Exec(sql, dashboard.OrgId, dashboard.Id)
if err != nil {
return err
}
}
}
var existingRuleID int64
exists, err := sess.Table("alert_rule").Where("namespace_uid = (SELECT uid FROM dashboard WHERE id = ?)", dashboard.Id).Cols("id").Get(&existingRuleID)
if err != nil {
return err
}
if exists {
if !cmd.ForceDeleteFolderRules {
return fmt.Errorf("folder cannot be deleted: %w", models.ErrFolderContainsAlertRules)
}
// Delete all rules under this folder.
deleteNGAlertsByFolder := []string{
"DELETE FROM alert_rule WHERE namespace_uid = (SELECT uid FROM dashboard WHERE id = ?)",
"DELETE FROM alert_rule_version WHERE rule_namespace_uid = (SELECT uid FROM dashboard WHERE id = ?)",
}
for _, sql := range deleteNGAlertsByFolder {
_, err := sess.Exec(sql, dashboard.Id)
if err != nil {
return err
}
}
}
} else {
_, err = sess.Exec("DELETE FROM permission WHERE scope = ?", ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.Id, 10)))
if err != nil {
return err
}
}
if err := deleteAlertDefinition(dashboard.Id, sess); err != nil {
return err
}
for _, sql := range deletes {
_, err := sess.Exec(sql, dashboard.Id)
if err != nil {
return err
}
}
return nil
}
func (ss *SQLStore) GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
if len(query.DashboardIds) == 0 {

View File

@ -482,12 +482,6 @@ func (m *SQLStoreMock) GetDashboardTags(ctx context.Context, query *models.GetDa
return nil // TODO: Implement
}
func (m *SQLStoreMock) DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error {
cmd.Id = m.ExpectedDashboard.Id
cmd.OrgId = m.ExpectedDashboard.OrgId
return m.ExpectedError
}
func (m *SQLStoreMock) GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error {
return m.ExpectedError
}

View File

@ -105,7 +105,6 @@ type Store interface {
GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error
GetDashboardTags(ctx context.Context, query *models.GetDashboardTagsQuery) error
SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error
DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error
GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error
GetDashboardUIDById(ctx context.Context, query *models.GetDashboardRefByIdQuery) error
GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error