mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Orgs: Remove dependency on dashboard table for deletion (#98501)
This commit is contained in:
parent
14369c53ed
commit
68479d844b
@ -205,6 +205,7 @@ type HTTPServer struct {
|
|||||||
tempUserService tempUser.Service
|
tempUserService tempUser.Service
|
||||||
loginAttemptService loginAttempt.Service
|
loginAttemptService loginAttempt.Service
|
||||||
orgService org.Service
|
orgService org.Service
|
||||||
|
orgDeletionService org.DeletionService
|
||||||
TeamService team.Service
|
TeamService team.Service
|
||||||
accesscontrolService accesscontrol.Service
|
accesscontrolService accesscontrol.Service
|
||||||
annotationsRepo annotations.Repository
|
annotationsRepo annotations.Repository
|
||||||
@ -264,7 +265,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
|||||||
secretsMigrator secrets.Migrator, secretsPluginManager plugins.SecretsPluginManager, secretsService secrets.Service,
|
secretsMigrator secrets.Migrator, secretsPluginManager plugins.SecretsPluginManager, secretsService secrets.Service,
|
||||||
secretsPluginMigrator spm.SecretMigrationProvider, secretsStore secretsKV.SecretsKVStore,
|
secretsPluginMigrator spm.SecretMigrationProvider, secretsStore secretsKV.SecretsKVStore,
|
||||||
publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service,
|
publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service,
|
||||||
loginAttemptService loginAttempt.Service, orgService org.Service, teamService team.Service,
|
loginAttemptService loginAttempt.Service, orgService org.Service, orgDeletionService org.DeletionService, teamService team.Service,
|
||||||
accesscontrolService accesscontrol.Service, navTreeService navtree.Service,
|
accesscontrolService accesscontrol.Service, navTreeService navtree.Service,
|
||||||
annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService, oauthTokenService oauthtoken.OAuthTokenService,
|
annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService, oauthTokenService oauthtoken.OAuthTokenService,
|
||||||
statsService stats.Service, authnService authn.Service, pluginsCDNService *pluginscdn.Service, promGatherer prometheus.Gatherer,
|
statsService stats.Service, authnService authn.Service, pluginsCDNService *pluginscdn.Service, promGatherer prometheus.Gatherer,
|
||||||
@ -356,6 +357,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
|||||||
tempUserService: tempUserService,
|
tempUserService: tempUserService,
|
||||||
loginAttemptService: loginAttemptService,
|
loginAttemptService: loginAttemptService,
|
||||||
orgService: orgService,
|
orgService: orgService,
|
||||||
|
orgDeletionService: orgDeletionService,
|
||||||
TeamService: teamService,
|
TeamService: teamService,
|
||||||
navTreeService: navTreeService,
|
navTreeService: navTreeService,
|
||||||
accesscontrolService: accesscontrolService,
|
accesscontrolService: accesscontrolService,
|
||||||
|
@ -297,7 +297,7 @@ func (hs *HTTPServer) DeleteOrgByID(c *contextmodel.ReqContext) response.Respons
|
|||||||
return response.Error(http.StatusBadRequest, "Can not delete org for current user", nil)
|
return response.Error(http.StatusBadRequest, "Can not delete org for current user", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := hs.orgService.Delete(c.Req.Context(), &org.DeleteOrgCommand{ID: orgID}); err != nil {
|
if err := hs.orgDeletionService.Delete(c.Req.Context(), &org.DeleteOrgCommand{ID: orgID}); err != nil {
|
||||||
if errors.Is(err, org.ErrOrgNotFound) {
|
if errors.Is(err, org.ErrOrgNotFound) {
|
||||||
return response.Error(http.StatusNotFound, "Failed to delete organization. ID not found", nil)
|
return response.Error(http.StatusNotFound, "Failed to delete organization. ID not found", nil)
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,7 @@ func TestAPIEndpoint_DeleteOrgs(t *testing.T) {
|
|||||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||||
hs.Cfg = setting.NewCfg()
|
hs.Cfg = setting.NewCfg()
|
||||||
hs.orgService = &orgtest.FakeOrgService{ExpectedOrg: &org.Org{}}
|
hs.orgService = &orgtest.FakeOrgService{ExpectedOrg: &org.Org{}}
|
||||||
|
hs.orgDeletionService = &orgtest.FakeOrgDeletionService{}
|
||||||
hs.userService = &usertest.FakeUserService{ExpectedSignedInUser: &user.SignedInUser{OrgID: 1}}
|
hs.userService = &usertest.FakeUserService{ExpectedSignedInUser: &user.SignedInUser{OrgID: 1}}
|
||||||
hs.accesscontrolService = actest.FakeService{ExpectedPermissions: tt.permission}
|
hs.accesscontrolService = actest.FakeService{ExpectedPermissions: tt.permission}
|
||||||
hs.authnService = &authntest.FakeService{}
|
hs.authnService = &authntest.FakeService{}
|
||||||
|
@ -337,6 +337,7 @@ var wireBasicSet = wire.NewSet(
|
|||||||
starApi.ProvideApi,
|
starApi.ProvideApi,
|
||||||
userimpl.ProvideService,
|
userimpl.ProvideService,
|
||||||
orgimpl.ProvideService,
|
orgimpl.ProvideService,
|
||||||
|
orgimpl.ProvideDeletionService,
|
||||||
statsimpl.ProvideService,
|
statsimpl.ProvideService,
|
||||||
grpccontext.ProvideContextHandler,
|
grpccontext.ProvideContextHandler,
|
||||||
grpcserver.ProvideService,
|
grpcserver.ProvideService,
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
type DashboardService interface {
|
type DashboardService interface {
|
||||||
BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, validateProvisionedDashboard bool) (*SaveDashboardCommand, error)
|
BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, validateProvisionedDashboard bool) (*SaveDashboardCommand, error)
|
||||||
DeleteDashboard(ctx context.Context, dashboardId int64, dashboardUID string, orgId int64) error
|
DeleteDashboard(ctx context.Context, dashboardId int64, dashboardUID string, orgId int64) error
|
||||||
|
DeleteAllDashboards(ctx context.Context, orgID int64) error
|
||||||
FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)
|
FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)
|
||||||
// GetDashboard fetches a dashboard.
|
// GetDashboard fetches a dashboard.
|
||||||
// To fetch a dashboard under root by title should set the folder UID to point to an empty string
|
// To fetch a dashboard under root by title should set the folder UID to point to an empty string
|
||||||
@ -60,6 +61,7 @@ type DashboardProvisioningService interface {
|
|||||||
//go:generate mockery --name Store --structname FakeDashboardStore --inpackage --filename store_mock.go
|
//go:generate mockery --name Store --structname FakeDashboardStore --inpackage --filename store_mock.go
|
||||||
type Store interface {
|
type Store interface {
|
||||||
DeleteDashboard(ctx context.Context, cmd *DeleteDashboardCommand) error
|
DeleteDashboard(ctx context.Context, cmd *DeleteDashboardCommand) error
|
||||||
|
DeleteAllDashboards(ctx context.Context, orgID int64) error
|
||||||
DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *DeleteOrphanedProvisionedDashboardsCommand) error
|
DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *DeleteOrphanedProvisionedDashboardsCommand) error
|
||||||
FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)
|
FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)
|
||||||
GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error)
|
GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error)
|
||||||
|
@ -120,6 +120,24 @@ func (_m *FakeDashboardService) DeleteDashboard(ctx context.Context, dashboardId
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteAllDashboards provides a mock function with given fields: ctx, orgID
|
||||||
|
func (_m *FakeDashboardService) 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
|
||||||
|
}
|
||||||
|
|
||||||
// FindDashboards provides a mock function with given fields: ctx, query
|
// FindDashboards provides a mock function with given fields: ctx, query
|
||||||
func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
|
func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
|
||||||
ret := _m.Called(ctx, query)
|
ret := _m.Called(ctx, query)
|
||||||
|
@ -667,6 +667,16 @@ func (d *dashboardStore) deleteDashboard(cmd *dashboards.DeleteDashboardCommand,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dashboardStore) DeleteAllDashboards(ctx context.Context, orgID int64) error {
|
||||||
|
ctx, span := tracer.Start(ctx, "dashboards.database.DeleteAllDashboards")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
return d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||||
|
_, err := sess.Where("org_id = ?", orgID).Delete(&dashboards.Dashboard{})
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Remove me and handle nested deletions in the service with the DashboardPermissionsService
|
// FIXME: Remove me and handle nested deletions in the service with the DashboardPermissionsService
|
||||||
func (d *dashboardStore) deleteResourcePermissions(sess *db.Session, orgID int64, resourceScope string) error {
|
func (d *dashboardStore) deleteResourcePermissions(sess *db.Session, orgID int64, resourceScope string) error {
|
||||||
// retrieve all permissions for the resource scope and org id
|
// retrieve all permissions for the resource scope and org id
|
||||||
|
@ -240,6 +240,32 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
|
|||||||
require.NotContains(t, terms, "delete this")
|
require.NotContains(t, terms, "delete this")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to delete all dashboards for an org", func(t *testing.T) {
|
||||||
|
setup()
|
||||||
|
dash1 := insertTestDashboard(t, dashboardStore, "delete me", 1, 0, "", false, "delete this")
|
||||||
|
dash2 := insertTestDashboard(t, dashboardStore, "delete me2", 1, 0, "", false, "delete this2")
|
||||||
|
dash3 := insertTestDashboard(t, dashboardStore, "dont delete me", 2, 0, "", false, "dont delete me")
|
||||||
|
|
||||||
|
err := dashboardStore.DeleteAllDashboards(context.Background(), 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// no dashboards should exist for org 1
|
||||||
|
queryResult, err := dashboardStore.GetDashboards(context.Background(), &dashboards.GetDashboardsQuery{
|
||||||
|
OrgID: 1,
|
||||||
|
DashboardUIDs: []string{dash1.UID, dash2.UID},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, len(queryResult), 0)
|
||||||
|
|
||||||
|
// but we should still have one for org 2
|
||||||
|
queryResult, err = dashboardStore.GetDashboards(context.Background(), &dashboards.GetDashboardsQuery{
|
||||||
|
OrgID: 2,
|
||||||
|
DashboardUIDs: []string{dash3.UID},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, len(queryResult), 1)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Should be able to create dashboard", func(t *testing.T) {
|
t.Run("Should be able to create dashboard", func(t *testing.T) {
|
||||||
setup()
|
setup()
|
||||||
cmd := dashboards.SaveDashboardCommand{
|
cmd := dashboards.SaveDashboardCommand{
|
||||||
|
@ -511,6 +511,15 @@ func (dr *DashboardServiceImpl) DeleteDashboard(ctx context.Context, dashboardId
|
|||||||
return dr.deleteDashboard(ctx, dashboardId, dashboardUID, orgId, true)
|
return dr.deleteDashboard(ctx, dashboardId, dashboardUID, orgId, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteAllDashboards will delete all dashboards within a given org.
|
||||||
|
func (dr *DashboardServiceImpl) DeleteAllDashboards(ctx context.Context, orgId int64) error {
|
||||||
|
if dr.features.IsEnabledGlobally(featuremgmt.FlagKubernetesCliDashboards) {
|
||||||
|
return dr.deleteAllDashboardThroughK8s(ctx, orgId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dr.dashboardStore.DeleteAllDashboards(ctx, orgId)
|
||||||
|
}
|
||||||
|
|
||||||
func (dr *DashboardServiceImpl) GetDashboardByPublicUid(ctx context.Context, dashboardPublicUid string) (*dashboards.Dashboard, error) {
|
func (dr *DashboardServiceImpl) GetDashboardByPublicUid(ctx context.Context, dashboardPublicUid string) (*dashboards.Dashboard, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -1178,6 +1187,29 @@ func (dr *DashboardServiceImpl) saveDashboardThroughK8s(ctx context.Context, cmd
|
|||||||
return finalDash, nil
|
return finalDash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dr *DashboardServiceImpl) deleteAllDashboardThroughK8s(ctx context.Context, orgID int64) error {
|
||||||
|
// create a new context - prevents issues when the request stems from the k8s api itself
|
||||||
|
// otherwise the context goes through the handlers twice and causes issues
|
||||||
|
newCtx, cancel, err := dr.getK8sContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if cancel != nil {
|
||||||
|
defer cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
client, ok := dr.k8sclient.getClient(newCtx, orgID)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("could not get k8s client")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.DeleteCollection(newCtx, v1.DeleteOptions{}, v1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (dr *DashboardServiceImpl) deleteDashboardThroughK8s(ctx context.Context, cmd *dashboards.DeleteDashboardCommand) error {
|
func (dr *DashboardServiceImpl) deleteDashboardThroughK8s(ctx context.Context, cmd *dashboards.DeleteDashboardCommand) error {
|
||||||
// create a new context - prevents issues when the request stems from the k8s api itself
|
// create a new context - prevents issues when the request stems from the k8s api itself
|
||||||
// otherwise the context goes through the handlers twice and causes issues
|
// otherwise the context goes through the handlers twice and causes issues
|
||||||
|
@ -305,6 +305,11 @@ func (m *mockResourceInterface) Delete(ctx context.Context, name string, options
|
|||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockResourceInterface) DeleteCollection(ctx context.Context, options metav1.DeleteOptions, listOptions metav1.ListOptions) error {
|
||||||
|
args := m.Called(ctx, options, listOptions)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
func setupK8sDashboardTests(service *DashboardServiceImpl) (context.Context, *mockDashK8sCli, *mockResourceInterface) {
|
func setupK8sDashboardTests(service *DashboardServiceImpl) (context.Context, *mockDashK8sCli, *mockResourceInterface) {
|
||||||
k8sClientMock := new(mockDashK8sCli)
|
k8sClientMock := new(mockDashK8sCli)
|
||||||
k8sResourceMock := new(mockResourceInterface)
|
k8sResourceMock := new(mockResourceInterface)
|
||||||
@ -644,6 +649,33 @@ func TestDeleteDashboard(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteAllDashboards(t *testing.T) {
|
||||||
|
fakeStore := dashboards.FakeDashboardStore{}
|
||||||
|
defer fakeStore.AssertExpectations(t)
|
||||||
|
service := &DashboardServiceImpl{
|
||||||
|
cfg: setting.NewCfg(),
|
||||||
|
dashboardStore: &fakeStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Should fallback to dashboard store if Kubernetes feature flags are not enabled", func(t *testing.T) {
|
||||||
|
service.features = featuremgmt.WithFeatures()
|
||||||
|
fakeStore.On("DeleteAllDashboards", mock.Anything, mock.Anything).Return(nil).Once()
|
||||||
|
err := service.DeleteAllDashboards(context.Background(), 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
fakeStore.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) {
|
||||||
|
ctx, k8sClientMock, k8sResourceMock := setupK8sDashboardTests(service)
|
||||||
|
k8sClientMock.On("getClient", mock.Anything, int64(1)).Return(k8sResourceMock, true).Once()
|
||||||
|
k8sResourceMock.On("DeleteCollection", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
|
||||||
|
|
||||||
|
err := service.DeleteAllDashboards(ctx, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
k8sClientMock.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestSearchDashboards(t *testing.T) {
|
func TestSearchDashboards(t *testing.T) {
|
||||||
fakeStore := dashboards.FakeDashboardStore{}
|
fakeStore := dashboards.FakeDashboardStore{}
|
||||||
defer fakeStore.AssertExpectations(t)
|
defer fakeStore.AssertExpectations(t)
|
||||||
|
@ -94,6 +94,24 @@ func (_m *FakeDashboardStore) DeleteDashboard(ctx context.Context, cmd *DeleteDa
|
|||||||
return r0
|
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
|
// DeleteDashboardsInFolders provides a mock function with given fields: ctx, request
|
||||||
func (_m *FakeDashboardStore) DeleteDashboardsInFolders(ctx context.Context, request *DeleteDashboardsInFolderRequest) error {
|
func (_m *FakeDashboardStore) DeleteDashboardsInFolders(ctx context.Context, request *DeleteDashboardsInFolderRequest) error {
|
||||||
ret := _m.Called(ctx, request)
|
ret := _m.Called(ctx, request)
|
||||||
|
@ -11,10 +11,12 @@ import (
|
|||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/folder"
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||||
@ -975,10 +977,14 @@ func CreateOrg(t *testing.T, db db.DB, cfg *setting.Cfg) int64 {
|
|||||||
|
|
||||||
orgService, err := orgimpl.ProvideService(db, cfg, quotatest.New(false, nil))
|
orgService, err := orgimpl.ProvideService(db, cfg, quotatest.New(false, nil))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
dashSvc := &dashboards.FakeDashboardService{}
|
||||||
|
dashSvc.On("DeleteAllDashboards", mock.Anything, mock.Anything).Return(nil)
|
||||||
|
deleteOrgService, err := orgimpl.ProvideDeletionService(db, cfg, dashSvc)
|
||||||
|
require.NoError(t, err)
|
||||||
orgID, err := orgService.GetOrCreate(context.Background(), "test-org")
|
orgID, err := orgService.GetOrCreate(context.Background(), "test-org")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
err = orgService.Delete(context.Background(), &org.DeleteOrgCommand{ID: orgID})
|
err = deleteOrgService.Delete(context.Background(), &org.DeleteOrgCommand{ID: orgID})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ type Service interface {
|
|||||||
GetByName(context.Context, *GetOrgByNameQuery) (*Org, error)
|
GetByName(context.Context, *GetOrgByNameQuery) (*Org, error)
|
||||||
CreateWithMember(context.Context, *CreateOrgCommand) (*Org, error)
|
CreateWithMember(context.Context, *CreateOrgCommand) (*Org, error)
|
||||||
UpdateAddress(context.Context, *UpdateOrgAddressCommand) error
|
UpdateAddress(context.Context, *UpdateOrgAddressCommand) error
|
||||||
Delete(context.Context, *DeleteOrgCommand) error
|
|
||||||
GetOrCreate(context.Context, string) (int64, error)
|
GetOrCreate(context.Context, string) (int64, error)
|
||||||
AddOrgUser(context.Context, *AddOrgUserCommand) error
|
AddOrgUser(context.Context, *AddOrgUserCommand) error
|
||||||
UpdateOrgUser(context.Context, *UpdateOrgUserCommand) error
|
UpdateOrgUser(context.Context, *UpdateOrgUserCommand) error
|
||||||
@ -25,3 +24,7 @@ type Service interface {
|
|||||||
SearchOrgUsers(context.Context, *SearchOrgUsersQuery) (*SearchOrgUsersQueryResult, error)
|
SearchOrgUsers(context.Context, *SearchOrgUsersQuery) (*SearchOrgUsersQueryResult, error)
|
||||||
RegisterDelete(query string)
|
RegisterDelete(query string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeletionService interface {
|
||||||
|
Delete(context.Context, *DeleteOrgCommand) error
|
||||||
|
}
|
||||||
|
@ -138,11 +138,6 @@ func (s *Service) UpdateAddress(ctx context.Context, cmd *org.UpdateOrgAddressCo
|
|||||||
return s.store.UpdateAddress(ctx, cmd)
|
return s.store.UpdateAddress(ctx, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor service to call store CRUD method
|
|
||||||
func (s *Service) Delete(ctx context.Context, cmd *org.DeleteOrgCommand) error {
|
|
||||||
return s.store.Delete(ctx, cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetOrCreate(ctx context.Context, orgName string) (int64, error) {
|
func (s *Service) GetOrCreate(ctx context.Context, orgName string) (int64, error) {
|
||||||
var orga = &org.Org{}
|
var orga = &org.Org{}
|
||||||
var err error
|
var err error
|
||||||
|
43
pkg/services/org/orgimpl/org_delete_svc.go
Normal file
43
pkg/services/org/orgimpl/org_delete_svc.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package orgimpl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeletionService struct {
|
||||||
|
store store
|
||||||
|
cfg *setting.Cfg
|
||||||
|
log log.Logger
|
||||||
|
dashSvc dashboards.DashboardService
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProvideDeletionService(db db.DB, cfg *setting.Cfg, dashboardService dashboards.DashboardService) (org.DeletionService, error) {
|
||||||
|
log := log.New("org deletion service")
|
||||||
|
s := &DeletionService{
|
||||||
|
store: &sqlStore{
|
||||||
|
db: db,
|
||||||
|
dialect: db.GetDialect(),
|
||||||
|
log: log,
|
||||||
|
},
|
||||||
|
cfg: cfg,
|
||||||
|
dashSvc: dashboardService,
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DeletionService) Delete(ctx context.Context, cmd *org.DeleteOrgCommand) error {
|
||||||
|
err := s.dashSvc.DeleteAllDashboards(ctx, cmd.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.store.Delete(ctx, cmd)
|
||||||
|
}
|
@ -220,9 +220,8 @@ func (ss *sqlStore) Delete(ctx context.Context, cmd *org.DeleteOrgCommand) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
deletes := []string{
|
deletes := []string{
|
||||||
"DELETE FROM star WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ? AND star.dashboard_uid = dashboard.uid)",
|
"DELETE FROM star WHERE org_id = ?",
|
||||||
"DELETE FROM dashboard_tag WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ? AND dashboard_tag.dashboard_id = dashboard.id)",
|
"DELETE FROM dashboard_tag WHERE org_id = ?",
|
||||||
"DELETE FROM dashboard WHERE org_id = ?",
|
|
||||||
"DELETE FROM api_key WHERE org_id = ?",
|
"DELETE FROM api_key WHERE org_id = ?",
|
||||||
"DELETE FROM data_source WHERE org_id = ?",
|
"DELETE FROM data_source WHERE org_id = ?",
|
||||||
"DELETE FROM org_user WHERE org_id = ?",
|
"DELETE FROM org_user WHERE org_id = ?",
|
||||||
|
@ -75,10 +75,6 @@ func (f *FakeOrgService) UpdateAddress(ctx context.Context, cmd *org.UpdateOrgAd
|
|||||||
return f.ExpectedError
|
return f.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeOrgService) Delete(ctx context.Context, cmd *org.DeleteOrgCommand) error {
|
|
||||||
return f.ExpectedError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeOrgService) GetOrCreate(ctx context.Context, orgName string) (int64, error) {
|
func (f *FakeOrgService) GetOrCreate(ctx context.Context, orgName string) (int64, error) {
|
||||||
return f.ExpectedOrg.ID, f.ExpectedError
|
return f.ExpectedOrg.ID, f.ExpectedError
|
||||||
}
|
}
|
||||||
@ -107,3 +103,15 @@ func (f *FakeOrgService) SearchOrgUsers(ctx context.Context, query *org.SearchOr
|
|||||||
|
|
||||||
func (f *FakeOrgService) RegisterDelete(query string) {
|
func (f *FakeOrgService) RegisterDelete(query string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FakeOrgDeletionService struct {
|
||||||
|
ExpectedError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOrgDeletionServiceFake() *FakeOrgDeletionService {
|
||||||
|
return &FakeOrgDeletionService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeOrgDeletionService) Delete(ctx context.Context, cmd *org.DeleteOrgCommand) error {
|
||||||
|
return f.ExpectedError
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user