From fd434cab58b98f35225b0a77f255e8f07d56e206 Mon Sep 17 00:00:00 2001 From: Arati R <33031346+suntala@users.noreply.github.com> Date: Mon, 24 Apr 2023 15:57:28 +0200 Subject: [PATCH] NestedFolders: Add API endpoint for descendant count in a folder (#66550) * Add CountInFolder to RegistryService interface * Add folder children counts api route * Update fake GetFolderChildrenCounts * Add test for getting folder children counts * Add validation to folder children counts handler * Update openapi specs * Update pkg/services/folder/folderimpl/folder.go Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> --------- Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> --- pkg/api/api.go | 1 + pkg/api/folder.go | 34 + pkg/services/dashboards/dashboard.go | 3 +- .../dashboards/dashboard_service_mock.go | 594 +++++++++++++++++- .../dashboards/service/dashboard_service.go | 12 +- .../service/dashboard_service_test.go | 2 +- pkg/services/folder/folderimpl/folder.go | 22 + pkg/services/folder/folderimpl/folder_test.go | 61 ++ pkg/services/folder/foldertest/foldertest.go | 11 +- pkg/services/folder/model.go | 11 + pkg/services/folder/registry.go | 5 +- pkg/services/folder/service.go | 1 + public/api-merged.json | 47 ++ public/openapi3.json | 53 ++ 14 files changed, 821 insertions(+), 36 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 0455e0a3537..c19239757b6 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -458,6 +458,7 @@ func (hs *HTTPServer) registerRoutes() { folderUidRoute.Put("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersWrite, uidScope)), routing.Wrap(hs.UpdateFolder)) folderUidRoute.Post("/move", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersWrite, uidScope)), routing.Wrap(hs.MoveFolder)) folderUidRoute.Delete("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersDelete, uidScope)), routing.Wrap(hs.DeleteFolder)) + folderUidRoute.Get("/counts", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersRead, uidScope)), routing.Wrap(hs.GetFolderChildrenCounts)) folderUidRoute.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) { folderPermissionRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersPermissionsRead, uidScope)), routing.Wrap(hs.GetFolderPermissionList)) diff --git a/pkg/api/folder.go b/pkg/api/folder.go index e856cc26c9d..0f7e8db7261 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -294,6 +294,26 @@ func (hs *HTTPServer) DeleteFolder(c *contextmodel.ReqContext) response.Response return response.JSON(http.StatusOK, "") } +// swagger:route GET /folders/{folder_uid}/counts folders getFolderChildrenCounts +// +// Gets the count of each descendant of a folder by kind. The folder is identified by UID. +// +// Responses: +// 200: getFolderChildrenCountsResponse +// 401: unauthorisedError +// 403: forbiddenError +// 404: notFoundError +// 500: internalServerError +func (hs *HTTPServer) GetFolderChildrenCounts(c *contextmodel.ReqContext) response.Response { + uid := web.Params(c.Req)[":uid"] + counts, err := hs.folderService.GetChildrenCounts(c.Req.Context(), &folder.GetChildrenCountsQuery{OrgID: c.OrgID, UID: &uid, SignedInUser: c.SignedInUser}) + if err != nil { + return apierrors.ToFolderErrorResponse(err) + } + + return response.JSON(http.StatusOK, counts) +} + func (hs *HTTPServer) newToFolderDto(c *contextmodel.ReqContext, g guardian.DashboardGuardian, folder *folder.Folder) dtos.Folder { canEdit, _ := g.CanEdit() canSave, _ := g.CanSave() @@ -499,3 +519,17 @@ type DeleteFolderResponse struct { Message string `json:"message"` } `json:"body"` } + +// swagger:parameters getFolderChildrenCounts +type GetFolderChildrenCountsParams struct { + // in:path + // required:true + FolderUID string `json:"folder_uid"` +} + +// swagger:response getFolderChildrenCountsResponse +type GetFolderChildrenCountsResponse struct { + // The response message + // in: body + Body folder.ChildrenCounts `json:"body"` +} diff --git a/pkg/services/dashboards/dashboard.go b/pkg/services/dashboards/dashboard.go index 5cab7bb3170..54eccd29b18 100644 --- a/pkg/services/dashboards/dashboard.go +++ b/pkg/services/dashboards/dashboard.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/search/model" + "github.com/grafana/grafana/pkg/services/user" ) // DashboardService is a service for operating on dashboards. @@ -29,7 +30,7 @@ type DashboardService interface { SearchDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) (model.HitList, error) UpdateDashboardACL(ctx context.Context, uid int64, items []*DashboardACL) error DeleteACLByUser(ctx context.Context, userID int64) error - CountDashboardsInFolder(ctx context.Context, query *CountDashboardsInFolderQuery) (int64, error) + CountInFolder(ctx context.Context, orgID int64, uid string, user *user.SignedInUser) (int64, error) } // PluginService is a service for operating on plugin dashboards. diff --git a/pkg/services/dashboards/dashboard_service_mock.go b/pkg/services/dashboards/dashboard_service_mock.go index 0c374caa14a..e8884177e9a 100644 --- a/pkg/services/dashboards/dashboard_service_mock.go +++ b/pkg/services/dashboards/dashboard_service_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.16.0. DO NOT EDIT. +// Code generated by mockery v2.23.2. DO NOT EDIT. package dashboards @@ -9,6 +9,8 @@ import ( mock "github.com/stretchr/testify/mock" model "github.com/grafana/grafana/pkg/services/search/model" + + user "github.com/grafana/grafana/pkg/services/user" ) // FakeDashboardService is an autogenerated mock type for the DashboardService type @@ -16,11 +18,23 @@ type FakeDashboardService struct { mock.Mock } +type FakeDashboardService_Expecter struct { + mock *mock.Mock +} + +func (_m *FakeDashboardService) EXPECT() *FakeDashboardService_Expecter { + return &FakeDashboardService_Expecter{mock: &_m.Mock} +} + // BuildSaveDashboardCommand provides a mock function with given fields: ctx, dto, shouldValidateAlerts, validateProvisionedDashboard func (_m *FakeDashboardService) BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*SaveDashboardCommand, error) { ret := _m.Called(ctx, dto, shouldValidateAlerts, validateProvisionedDashboard) var r0 *SaveDashboardCommand + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO, bool, bool) (*SaveDashboardCommand, error)); ok { + return rf(ctx, dto, shouldValidateAlerts, validateProvisionedDashboard) + } if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO, bool, bool) *SaveDashboardCommand); ok { r0 = rf(ctx, dto, shouldValidateAlerts, validateProvisionedDashboard) } else { @@ -29,7 +43,6 @@ func (_m *FakeDashboardService) BuildSaveDashboardCommand(ctx context.Context, d } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *SaveDashboardDTO, bool, bool) error); ok { r1 = rf(ctx, dto, shouldValidateAlerts, validateProvisionedDashboard) } else { @@ -39,20 +52,54 @@ func (_m *FakeDashboardService) BuildSaveDashboardCommand(ctx context.Context, d return r0, r1 } -// CountDashboardsInFolder provides a mock function with given fields: ctx, query -func (_m *FakeDashboardService) CountDashboardsInFolder(ctx context.Context, query *CountDashboardsInFolderQuery) (int64, error) { - ret := _m.Called(ctx, query) +// FakeDashboardService_BuildSaveDashboardCommand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuildSaveDashboardCommand' +type FakeDashboardService_BuildSaveDashboardCommand_Call struct { + *mock.Call +} + +// BuildSaveDashboardCommand is a helper method to define mock.On call +// - ctx context.Context +// - dto *SaveDashboardDTO +// - shouldValidateAlerts bool +// - validateProvisionedDashboard bool +func (_e *FakeDashboardService_Expecter) BuildSaveDashboardCommand(ctx interface{}, dto interface{}, shouldValidateAlerts interface{}, validateProvisionedDashboard interface{}) *FakeDashboardService_BuildSaveDashboardCommand_Call { + return &FakeDashboardService_BuildSaveDashboardCommand_Call{Call: _e.mock.On("BuildSaveDashboardCommand", ctx, dto, shouldValidateAlerts, validateProvisionedDashboard)} +} + +func (_c *FakeDashboardService_BuildSaveDashboardCommand_Call) Run(run func(ctx context.Context, dto *SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool)) *FakeDashboardService_BuildSaveDashboardCommand_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*SaveDashboardDTO), args[2].(bool), args[3].(bool)) + }) + return _c +} + +func (_c *FakeDashboardService_BuildSaveDashboardCommand_Call) Return(_a0 *SaveDashboardCommand, _a1 error) *FakeDashboardService_BuildSaveDashboardCommand_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_BuildSaveDashboardCommand_Call) RunAndReturn(run func(context.Context, *SaveDashboardDTO, bool, bool) (*SaveDashboardCommand, error)) *FakeDashboardService_BuildSaveDashboardCommand_Call { + _c.Call.Return(run) + return _c +} + +// CountInFolder provides a mock function with given fields: ctx, orgID, uid, _a3 +func (_m *FakeDashboardService) CountInFolder(ctx context.Context, orgID int64, uid string, _a3 *user.SignedInUser) (int64, error) { + ret := _m.Called(ctx, orgID, uid, _a3) var r0 int64 - if rf, ok := ret.Get(0).(func(context.Context, *CountDashboardsInFolderQuery) int64); ok { - r0 = rf(ctx, query) + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, *user.SignedInUser) (int64, error)); ok { + return rf(ctx, orgID, uid, _a3) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, *user.SignedInUser) int64); ok { + r0 = rf(ctx, orgID, uid, _a3) } else { r0 = ret.Get(0).(int64) } - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *CountDashboardsInFolderQuery) error); ok { - r1 = rf(ctx, query) + if rf, ok := ret.Get(1).(func(context.Context, int64, string, *user.SignedInUser) error); ok { + r1 = rf(ctx, orgID, uid, _a3) } else { r1 = ret.Error(1) } @@ -60,6 +107,37 @@ func (_m *FakeDashboardService) CountDashboardsInFolder(ctx context.Context, que return r0, r1 } +// FakeDashboardService_CountInFolder_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CountInFolder' +type FakeDashboardService_CountInFolder_Call struct { + *mock.Call +} + +// CountInFolder is a helper method to define mock.On call +// - ctx context.Context +// - orgID int64 +// - uid string +// - _a3 *user.SignedInUser +func (_e *FakeDashboardService_Expecter) CountInFolder(ctx interface{}, orgID interface{}, uid interface{}, _a3 interface{}) *FakeDashboardService_CountInFolder_Call { + return &FakeDashboardService_CountInFolder_Call{Call: _e.mock.On("CountInFolder", ctx, orgID, uid, _a3)} +} + +func (_c *FakeDashboardService_CountInFolder_Call) Run(run func(ctx context.Context, orgID int64, uid string, _a3 *user.SignedInUser)) *FakeDashboardService_CountInFolder_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64), args[2].(string), args[3].(*user.SignedInUser)) + }) + return _c +} + +func (_c *FakeDashboardService_CountInFolder_Call) Return(_a0 int64, _a1 error) *FakeDashboardService_CountInFolder_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_CountInFolder_Call) RunAndReturn(run func(context.Context, int64, string, *user.SignedInUser) (int64, error)) *FakeDashboardService_CountInFolder_Call { + _c.Call.Return(run) + return _c +} + // DeleteACLByUser provides a mock function with given fields: ctx, userID func (_m *FakeDashboardService) DeleteACLByUser(ctx context.Context, userID int64) error { ret := _m.Called(ctx, userID) @@ -74,6 +152,35 @@ func (_m *FakeDashboardService) DeleteACLByUser(ctx context.Context, userID int6 return r0 } +// FakeDashboardService_DeleteACLByUser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteACLByUser' +type FakeDashboardService_DeleteACLByUser_Call struct { + *mock.Call +} + +// DeleteACLByUser is a helper method to define mock.On call +// - ctx context.Context +// - userID int64 +func (_e *FakeDashboardService_Expecter) DeleteACLByUser(ctx interface{}, userID interface{}) *FakeDashboardService_DeleteACLByUser_Call { + return &FakeDashboardService_DeleteACLByUser_Call{Call: _e.mock.On("DeleteACLByUser", ctx, userID)} +} + +func (_c *FakeDashboardService_DeleteACLByUser_Call) Run(run func(ctx context.Context, userID int64)) *FakeDashboardService_DeleteACLByUser_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *FakeDashboardService_DeleteACLByUser_Call) Return(_a0 error) *FakeDashboardService_DeleteACLByUser_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FakeDashboardService_DeleteACLByUser_Call) RunAndReturn(run func(context.Context, int64) error) *FakeDashboardService_DeleteACLByUser_Call { + _c.Call.Return(run) + return _c +} + // DeleteDashboard provides a mock function with given fields: ctx, dashboardId, orgId func (_m *FakeDashboardService) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error { ret := _m.Called(ctx, dashboardId, orgId) @@ -88,11 +195,45 @@ func (_m *FakeDashboardService) DeleteDashboard(ctx context.Context, dashboardId return r0 } +// FakeDashboardService_DeleteDashboard_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteDashboard' +type FakeDashboardService_DeleteDashboard_Call struct { + *mock.Call +} + +// DeleteDashboard is a helper method to define mock.On call +// - ctx context.Context +// - dashboardId int64 +// - orgId int64 +func (_e *FakeDashboardService_Expecter) DeleteDashboard(ctx interface{}, dashboardId interface{}, orgId interface{}) *FakeDashboardService_DeleteDashboard_Call { + return &FakeDashboardService_DeleteDashboard_Call{Call: _e.mock.On("DeleteDashboard", ctx, dashboardId, orgId)} +} + +func (_c *FakeDashboardService_DeleteDashboard_Call) Run(run func(ctx context.Context, dashboardId int64, orgId int64)) *FakeDashboardService_DeleteDashboard_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64), args[2].(int64)) + }) + return _c +} + +func (_c *FakeDashboardService_DeleteDashboard_Call) Return(_a0 error) *FakeDashboardService_DeleteDashboard_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FakeDashboardService_DeleteDashboard_Call) RunAndReturn(run func(context.Context, int64, int64) error) *FakeDashboardService_DeleteDashboard_Call { + _c.Call.Return(run) + return _c +} + // FindDashboards provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) { ret := _m.Called(ctx, query) var r0 []DashboardSearchProjection + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *FindPersistedDashboardsQuery) []DashboardSearchProjection); ok { r0 = rf(ctx, query) } else { @@ -101,7 +242,6 @@ func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindP } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *FindPersistedDashboardsQuery) error); ok { r1 = rf(ctx, query) } else { @@ -111,11 +251,44 @@ func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindP return r0, r1 } +// FakeDashboardService_FindDashboards_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindDashboards' +type FakeDashboardService_FindDashboards_Call struct { + *mock.Call +} + +// FindDashboards is a helper method to define mock.On call +// - ctx context.Context +// - query *FindPersistedDashboardsQuery +func (_e *FakeDashboardService_Expecter) FindDashboards(ctx interface{}, query interface{}) *FakeDashboardService_FindDashboards_Call { + return &FakeDashboardService_FindDashboards_Call{Call: _e.mock.On("FindDashboards", ctx, query)} +} + +func (_c *FakeDashboardService_FindDashboards_Call) Run(run func(ctx context.Context, query *FindPersistedDashboardsQuery)) *FakeDashboardService_FindDashboards_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*FindPersistedDashboardsQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_FindDashboards_Call) Return(_a0 []DashboardSearchProjection, _a1 error) *FakeDashboardService_FindDashboards_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_FindDashboards_Call) RunAndReturn(run func(context.Context, *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)) *FakeDashboardService_FindDashboards_Call { + _c.Call.Return(run) + return _c +} + // GetDashboard provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error) { ret := _m.Called(ctx, query) var r0 *Dashboard + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardQuery) (*Dashboard, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardQuery) *Dashboard); ok { r0 = rf(ctx, query) } else { @@ -124,7 +297,6 @@ func (_m *FakeDashboardService) GetDashboard(ctx context.Context, query *GetDash } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *GetDashboardQuery) error); ok { r1 = rf(ctx, query) } else { @@ -134,11 +306,44 @@ func (_m *FakeDashboardService) GetDashboard(ctx context.Context, query *GetDash return r0, r1 } +// FakeDashboardService_GetDashboard_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDashboard' +type FakeDashboardService_GetDashboard_Call struct { + *mock.Call +} + +// GetDashboard is a helper method to define mock.On call +// - ctx context.Context +// - query *GetDashboardQuery +func (_e *FakeDashboardService_Expecter) GetDashboard(ctx interface{}, query interface{}) *FakeDashboardService_GetDashboard_Call { + return &FakeDashboardService_GetDashboard_Call{Call: _e.mock.On("GetDashboard", ctx, query)} +} + +func (_c *FakeDashboardService_GetDashboard_Call) Run(run func(ctx context.Context, query *GetDashboardQuery)) *FakeDashboardService_GetDashboard_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*GetDashboardQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_GetDashboard_Call) Return(_a0 *Dashboard, _a1 error) *FakeDashboardService_GetDashboard_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_GetDashboard_Call) RunAndReturn(run func(context.Context, *GetDashboardQuery) (*Dashboard, error)) *FakeDashboardService_GetDashboard_Call { + _c.Call.Return(run) + return _c +} + // GetDashboardACLInfoList provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) GetDashboardACLInfoList(ctx context.Context, query *GetDashboardACLInfoListQuery) ([]*DashboardACLInfoDTO, error) { ret := _m.Called(ctx, query) var r0 []*DashboardACLInfoDTO + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardACLInfoListQuery) ([]*DashboardACLInfoDTO, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardACLInfoListQuery) []*DashboardACLInfoDTO); ok { r0 = rf(ctx, query) } else { @@ -147,7 +352,6 @@ func (_m *FakeDashboardService) GetDashboardACLInfoList(ctx context.Context, que } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *GetDashboardACLInfoListQuery) error); ok { r1 = rf(ctx, query) } else { @@ -157,11 +361,44 @@ func (_m *FakeDashboardService) GetDashboardACLInfoList(ctx context.Context, que return r0, r1 } +// FakeDashboardService_GetDashboardACLInfoList_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDashboardACLInfoList' +type FakeDashboardService_GetDashboardACLInfoList_Call struct { + *mock.Call +} + +// GetDashboardACLInfoList is a helper method to define mock.On call +// - ctx context.Context +// - query *GetDashboardACLInfoListQuery +func (_e *FakeDashboardService_Expecter) GetDashboardACLInfoList(ctx interface{}, query interface{}) *FakeDashboardService_GetDashboardACLInfoList_Call { + return &FakeDashboardService_GetDashboardACLInfoList_Call{Call: _e.mock.On("GetDashboardACLInfoList", ctx, query)} +} + +func (_c *FakeDashboardService_GetDashboardACLInfoList_Call) Run(run func(ctx context.Context, query *GetDashboardACLInfoListQuery)) *FakeDashboardService_GetDashboardACLInfoList_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*GetDashboardACLInfoListQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_GetDashboardACLInfoList_Call) Return(_a0 []*DashboardACLInfoDTO, _a1 error) *FakeDashboardService_GetDashboardACLInfoList_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_GetDashboardACLInfoList_Call) RunAndReturn(run func(context.Context, *GetDashboardACLInfoListQuery) ([]*DashboardACLInfoDTO, error)) *FakeDashboardService_GetDashboardACLInfoList_Call { + _c.Call.Return(run) + return _c +} + // GetDashboardTags provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) GetDashboardTags(ctx context.Context, query *GetDashboardTagsQuery) ([]*DashboardTagCloudItem, error) { ret := _m.Called(ctx, query) var r0 []*DashboardTagCloudItem + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardTagsQuery) ([]*DashboardTagCloudItem, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardTagsQuery) []*DashboardTagCloudItem); ok { r0 = rf(ctx, query) } else { @@ -170,7 +407,6 @@ func (_m *FakeDashboardService) GetDashboardTags(ctx context.Context, query *Get } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *GetDashboardTagsQuery) error); ok { r1 = rf(ctx, query) } else { @@ -180,11 +416,44 @@ func (_m *FakeDashboardService) GetDashboardTags(ctx context.Context, query *Get return r0, r1 } +// FakeDashboardService_GetDashboardTags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDashboardTags' +type FakeDashboardService_GetDashboardTags_Call struct { + *mock.Call +} + +// GetDashboardTags is a helper method to define mock.On call +// - ctx context.Context +// - query *GetDashboardTagsQuery +func (_e *FakeDashboardService_Expecter) GetDashboardTags(ctx interface{}, query interface{}) *FakeDashboardService_GetDashboardTags_Call { + return &FakeDashboardService_GetDashboardTags_Call{Call: _e.mock.On("GetDashboardTags", ctx, query)} +} + +func (_c *FakeDashboardService_GetDashboardTags_Call) Run(run func(ctx context.Context, query *GetDashboardTagsQuery)) *FakeDashboardService_GetDashboardTags_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*GetDashboardTagsQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_GetDashboardTags_Call) Return(_a0 []*DashboardTagCloudItem, _a1 error) *FakeDashboardService_GetDashboardTags_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_GetDashboardTags_Call) RunAndReturn(run func(context.Context, *GetDashboardTagsQuery) ([]*DashboardTagCloudItem, error)) *FakeDashboardService_GetDashboardTags_Call { + _c.Call.Return(run) + return _c +} + // GetDashboardUIDByID provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) GetDashboardUIDByID(ctx context.Context, query *GetDashboardRefByIDQuery) (*DashboardRef, error) { ret := _m.Called(ctx, query) var r0 *DashboardRef + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardRefByIDQuery) (*DashboardRef, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardRefByIDQuery) *DashboardRef); ok { r0 = rf(ctx, query) } else { @@ -193,7 +462,6 @@ func (_m *FakeDashboardService) GetDashboardUIDByID(ctx context.Context, query * } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *GetDashboardRefByIDQuery) error); ok { r1 = rf(ctx, query) } else { @@ -203,11 +471,44 @@ func (_m *FakeDashboardService) GetDashboardUIDByID(ctx context.Context, query * return r0, r1 } +// FakeDashboardService_GetDashboardUIDByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDashboardUIDByID' +type FakeDashboardService_GetDashboardUIDByID_Call struct { + *mock.Call +} + +// GetDashboardUIDByID is a helper method to define mock.On call +// - ctx context.Context +// - query *GetDashboardRefByIDQuery +func (_e *FakeDashboardService_Expecter) GetDashboardUIDByID(ctx interface{}, query interface{}) *FakeDashboardService_GetDashboardUIDByID_Call { + return &FakeDashboardService_GetDashboardUIDByID_Call{Call: _e.mock.On("GetDashboardUIDByID", ctx, query)} +} + +func (_c *FakeDashboardService_GetDashboardUIDByID_Call) Run(run func(ctx context.Context, query *GetDashboardRefByIDQuery)) *FakeDashboardService_GetDashboardUIDByID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*GetDashboardRefByIDQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_GetDashboardUIDByID_Call) Return(_a0 *DashboardRef, _a1 error) *FakeDashboardService_GetDashboardUIDByID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_GetDashboardUIDByID_Call) RunAndReturn(run func(context.Context, *GetDashboardRefByIDQuery) (*DashboardRef, error)) *FakeDashboardService_GetDashboardUIDByID_Call { + _c.Call.Return(run) + return _c +} + // GetDashboards provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) GetDashboards(ctx context.Context, query *GetDashboardsQuery) ([]*Dashboard, error) { ret := _m.Called(ctx, query) var r0 []*Dashboard + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardsQuery) ([]*Dashboard, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardsQuery) []*Dashboard); ok { r0 = rf(ctx, query) } else { @@ -216,7 +517,6 @@ func (_m *FakeDashboardService) GetDashboards(ctx context.Context, query *GetDas } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *GetDashboardsQuery) error); ok { r1 = rf(ctx, query) } else { @@ -226,18 +526,50 @@ func (_m *FakeDashboardService) GetDashboards(ctx context.Context, query *GetDas return r0, r1 } +// FakeDashboardService_GetDashboards_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDashboards' +type FakeDashboardService_GetDashboards_Call struct { + *mock.Call +} + +// GetDashboards is a helper method to define mock.On call +// - ctx context.Context +// - query *GetDashboardsQuery +func (_e *FakeDashboardService_Expecter) GetDashboards(ctx interface{}, query interface{}) *FakeDashboardService_GetDashboards_Call { + return &FakeDashboardService_GetDashboards_Call{Call: _e.mock.On("GetDashboards", ctx, query)} +} + +func (_c *FakeDashboardService_GetDashboards_Call) Run(run func(ctx context.Context, query *GetDashboardsQuery)) *FakeDashboardService_GetDashboards_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*GetDashboardsQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_GetDashboards_Call) Return(_a0 []*Dashboard, _a1 error) *FakeDashboardService_GetDashboards_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_GetDashboards_Call) RunAndReturn(run func(context.Context, *GetDashboardsQuery) ([]*Dashboard, error)) *FakeDashboardService_GetDashboards_Call { + _c.Call.Return(run) + return _c +} + // HasAdminPermissionInDashboardsOrFolders provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) HasAdminPermissionInDashboardsOrFolders(ctx context.Context, query *folder.HasAdminPermissionInDashboardsOrFoldersQuery) (bool, error) { ret := _m.Called(ctx, query) var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *folder.HasAdminPermissionInDashboardsOrFoldersQuery) (bool, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *folder.HasAdminPermissionInDashboardsOrFoldersQuery) bool); ok { r0 = rf(ctx, query) } else { r0 = ret.Get(0).(bool) } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *folder.HasAdminPermissionInDashboardsOrFoldersQuery) error); ok { r1 = rf(ctx, query) } else { @@ -247,18 +579,50 @@ func (_m *FakeDashboardService) HasAdminPermissionInDashboardsOrFolders(ctx cont return r0, r1 } +// FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasAdminPermissionInDashboardsOrFolders' +type FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call struct { + *mock.Call +} + +// HasAdminPermissionInDashboardsOrFolders is a helper method to define mock.On call +// - ctx context.Context +// - query *folder.HasAdminPermissionInDashboardsOrFoldersQuery +func (_e *FakeDashboardService_Expecter) HasAdminPermissionInDashboardsOrFolders(ctx interface{}, query interface{}) *FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call { + return &FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call{Call: _e.mock.On("HasAdminPermissionInDashboardsOrFolders", ctx, query)} +} + +func (_c *FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call) Run(run func(ctx context.Context, query *folder.HasAdminPermissionInDashboardsOrFoldersQuery)) *FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*folder.HasAdminPermissionInDashboardsOrFoldersQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call) Return(_a0 bool, _a1 error) *FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call) RunAndReturn(run func(context.Context, *folder.HasAdminPermissionInDashboardsOrFoldersQuery) (bool, error)) *FakeDashboardService_HasAdminPermissionInDashboardsOrFolders_Call { + _c.Call.Return(run) + return _c +} + // HasEditPermissionInFolders provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) HasEditPermissionInFolders(ctx context.Context, query *folder.HasEditPermissionInFoldersQuery) (bool, error) { ret := _m.Called(ctx, query) var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *folder.HasEditPermissionInFoldersQuery) (bool, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *folder.HasEditPermissionInFoldersQuery) bool); ok { r0 = rf(ctx, query) } else { r0 = ret.Get(0).(bool) } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *folder.HasEditPermissionInFoldersQuery) error); ok { r1 = rf(ctx, query) } else { @@ -268,11 +632,44 @@ func (_m *FakeDashboardService) HasEditPermissionInFolders(ctx context.Context, return r0, r1 } +// FakeDashboardService_HasEditPermissionInFolders_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasEditPermissionInFolders' +type FakeDashboardService_HasEditPermissionInFolders_Call struct { + *mock.Call +} + +// HasEditPermissionInFolders is a helper method to define mock.On call +// - ctx context.Context +// - query *folder.HasEditPermissionInFoldersQuery +func (_e *FakeDashboardService_Expecter) HasEditPermissionInFolders(ctx interface{}, query interface{}) *FakeDashboardService_HasEditPermissionInFolders_Call { + return &FakeDashboardService_HasEditPermissionInFolders_Call{Call: _e.mock.On("HasEditPermissionInFolders", ctx, query)} +} + +func (_c *FakeDashboardService_HasEditPermissionInFolders_Call) Run(run func(ctx context.Context, query *folder.HasEditPermissionInFoldersQuery)) *FakeDashboardService_HasEditPermissionInFolders_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*folder.HasEditPermissionInFoldersQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_HasEditPermissionInFolders_Call) Return(_a0 bool, _a1 error) *FakeDashboardService_HasEditPermissionInFolders_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_HasEditPermissionInFolders_Call) RunAndReturn(run func(context.Context, *folder.HasEditPermissionInFoldersQuery) (bool, error)) *FakeDashboardService_HasEditPermissionInFolders_Call { + _c.Call.Return(run) + return _c +} + // ImportDashboard provides a mock function with given fields: ctx, dto func (_m *FakeDashboardService) ImportDashboard(ctx context.Context, dto *SaveDashboardDTO) (*Dashboard, error) { ret := _m.Called(ctx, dto) var r0 *Dashboard + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO) (*Dashboard, error)); ok { + return rf(ctx, dto) + } if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO) *Dashboard); ok { r0 = rf(ctx, dto) } else { @@ -281,7 +678,6 @@ func (_m *FakeDashboardService) ImportDashboard(ctx context.Context, dto *SaveDa } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *SaveDashboardDTO) error); ok { r1 = rf(ctx, dto) } else { @@ -291,6 +687,35 @@ func (_m *FakeDashboardService) ImportDashboard(ctx context.Context, dto *SaveDa return r0, r1 } +// FakeDashboardService_ImportDashboard_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ImportDashboard' +type FakeDashboardService_ImportDashboard_Call struct { + *mock.Call +} + +// ImportDashboard is a helper method to define mock.On call +// - ctx context.Context +// - dto *SaveDashboardDTO +func (_e *FakeDashboardService_Expecter) ImportDashboard(ctx interface{}, dto interface{}) *FakeDashboardService_ImportDashboard_Call { + return &FakeDashboardService_ImportDashboard_Call{Call: _e.mock.On("ImportDashboard", ctx, dto)} +} + +func (_c *FakeDashboardService_ImportDashboard_Call) Run(run func(ctx context.Context, dto *SaveDashboardDTO)) *FakeDashboardService_ImportDashboard_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*SaveDashboardDTO)) + }) + return _c +} + +func (_c *FakeDashboardService_ImportDashboard_Call) Return(_a0 *Dashboard, _a1 error) *FakeDashboardService_ImportDashboard_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_ImportDashboard_Call) RunAndReturn(run func(context.Context, *SaveDashboardDTO) (*Dashboard, error)) *FakeDashboardService_ImportDashboard_Call { + _c.Call.Return(run) + return _c +} + // MakeUserAdmin provides a mock function with given fields: ctx, orgID, userID, dashboardID, setViewAndEditPermissions func (_m *FakeDashboardService) MakeUserAdmin(ctx context.Context, orgID int64, userID int64, dashboardID int64, setViewAndEditPermissions bool) error { ret := _m.Called(ctx, orgID, userID, dashboardID, setViewAndEditPermissions) @@ -305,11 +730,47 @@ func (_m *FakeDashboardService) MakeUserAdmin(ctx context.Context, orgID int64, return r0 } +// FakeDashboardService_MakeUserAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MakeUserAdmin' +type FakeDashboardService_MakeUserAdmin_Call struct { + *mock.Call +} + +// MakeUserAdmin is a helper method to define mock.On call +// - ctx context.Context +// - orgID int64 +// - userID int64 +// - dashboardID int64 +// - setViewAndEditPermissions bool +func (_e *FakeDashboardService_Expecter) MakeUserAdmin(ctx interface{}, orgID interface{}, userID interface{}, dashboardID interface{}, setViewAndEditPermissions interface{}) *FakeDashboardService_MakeUserAdmin_Call { + return &FakeDashboardService_MakeUserAdmin_Call{Call: _e.mock.On("MakeUserAdmin", ctx, orgID, userID, dashboardID, setViewAndEditPermissions)} +} + +func (_c *FakeDashboardService_MakeUserAdmin_Call) Run(run func(ctx context.Context, orgID int64, userID int64, dashboardID int64, setViewAndEditPermissions bool)) *FakeDashboardService_MakeUserAdmin_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64), args[2].(int64), args[3].(int64), args[4].(bool)) + }) + return _c +} + +func (_c *FakeDashboardService_MakeUserAdmin_Call) Return(_a0 error) *FakeDashboardService_MakeUserAdmin_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FakeDashboardService_MakeUserAdmin_Call) RunAndReturn(run func(context.Context, int64, int64, int64, bool) error) *FakeDashboardService_MakeUserAdmin_Call { + _c.Call.Return(run) + return _c +} + // SaveDashboard provides a mock function with given fields: ctx, dto, allowUiUpdate func (_m *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*Dashboard, error) { ret := _m.Called(ctx, dto, allowUiUpdate) var r0 *Dashboard + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO, bool) (*Dashboard, error)); ok { + return rf(ctx, dto, allowUiUpdate) + } if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO, bool) *Dashboard); ok { r0 = rf(ctx, dto, allowUiUpdate) } else { @@ -318,7 +779,6 @@ func (_m *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDash } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *SaveDashboardDTO, bool) error); ok { r1 = rf(ctx, dto, allowUiUpdate) } else { @@ -328,11 +788,45 @@ func (_m *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDash return r0, r1 } +// FakeDashboardService_SaveDashboard_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveDashboard' +type FakeDashboardService_SaveDashboard_Call struct { + *mock.Call +} + +// SaveDashboard is a helper method to define mock.On call +// - ctx context.Context +// - dto *SaveDashboardDTO +// - allowUiUpdate bool +func (_e *FakeDashboardService_Expecter) SaveDashboard(ctx interface{}, dto interface{}, allowUiUpdate interface{}) *FakeDashboardService_SaveDashboard_Call { + return &FakeDashboardService_SaveDashboard_Call{Call: _e.mock.On("SaveDashboard", ctx, dto, allowUiUpdate)} +} + +func (_c *FakeDashboardService_SaveDashboard_Call) Run(run func(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool)) *FakeDashboardService_SaveDashboard_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*SaveDashboardDTO), args[2].(bool)) + }) + return _c +} + +func (_c *FakeDashboardService_SaveDashboard_Call) Return(_a0 *Dashboard, _a1 error) *FakeDashboardService_SaveDashboard_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_SaveDashboard_Call) RunAndReturn(run func(context.Context, *SaveDashboardDTO, bool) (*Dashboard, error)) *FakeDashboardService_SaveDashboard_Call { + _c.Call.Return(run) + return _c +} + // SearchDashboards provides a mock function with given fields: ctx, query func (_m *FakeDashboardService) SearchDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) (model.HitList, error) { ret := _m.Called(ctx, query) var r0 model.HitList + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *FindPersistedDashboardsQuery) (model.HitList, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *FindPersistedDashboardsQuery) model.HitList); ok { r0 = rf(ctx, query) } else { @@ -341,7 +835,6 @@ func (_m *FakeDashboardService) SearchDashboards(ctx context.Context, query *Fin } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *FindPersistedDashboardsQuery) error); ok { r1 = rf(ctx, query) } else { @@ -351,6 +844,35 @@ func (_m *FakeDashboardService) SearchDashboards(ctx context.Context, query *Fin return r0, r1 } +// FakeDashboardService_SearchDashboards_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SearchDashboards' +type FakeDashboardService_SearchDashboards_Call struct { + *mock.Call +} + +// SearchDashboards is a helper method to define mock.On call +// - ctx context.Context +// - query *FindPersistedDashboardsQuery +func (_e *FakeDashboardService_Expecter) SearchDashboards(ctx interface{}, query interface{}) *FakeDashboardService_SearchDashboards_Call { + return &FakeDashboardService_SearchDashboards_Call{Call: _e.mock.On("SearchDashboards", ctx, query)} +} + +func (_c *FakeDashboardService_SearchDashboards_Call) Run(run func(ctx context.Context, query *FindPersistedDashboardsQuery)) *FakeDashboardService_SearchDashboards_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*FindPersistedDashboardsQuery)) + }) + return _c +} + +func (_c *FakeDashboardService_SearchDashboards_Call) Return(_a0 model.HitList, _a1 error) *FakeDashboardService_SearchDashboards_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FakeDashboardService_SearchDashboards_Call) RunAndReturn(run func(context.Context, *FindPersistedDashboardsQuery) (model.HitList, error)) *FakeDashboardService_SearchDashboards_Call { + _c.Call.Return(run) + return _c +} + // UpdateDashboardACL provides a mock function with given fields: ctx, uid, items func (_m *FakeDashboardService) UpdateDashboardACL(ctx context.Context, uid int64, items []*DashboardACL) error { ret := _m.Called(ctx, uid, items) @@ -365,6 +887,36 @@ func (_m *FakeDashboardService) UpdateDashboardACL(ctx context.Context, uid int6 return r0 } +// FakeDashboardService_UpdateDashboardACL_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateDashboardACL' +type FakeDashboardService_UpdateDashboardACL_Call struct { + *mock.Call +} + +// UpdateDashboardACL is a helper method to define mock.On call +// - ctx context.Context +// - uid int64 +// - items []*DashboardACL +func (_e *FakeDashboardService_Expecter) UpdateDashboardACL(ctx interface{}, uid interface{}, items interface{}) *FakeDashboardService_UpdateDashboardACL_Call { + return &FakeDashboardService_UpdateDashboardACL_Call{Call: _e.mock.On("UpdateDashboardACL", ctx, uid, items)} +} + +func (_c *FakeDashboardService_UpdateDashboardACL_Call) Run(run func(ctx context.Context, uid int64, items []*DashboardACL)) *FakeDashboardService_UpdateDashboardACL_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64), args[2].([]*DashboardACL)) + }) + return _c +} + +func (_c *FakeDashboardService_UpdateDashboardACL_Call) Return(_a0 error) *FakeDashboardService_UpdateDashboardACL_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FakeDashboardService_UpdateDashboardACL_Call) RunAndReturn(run func(context.Context, int64, []*DashboardACL) error) *FakeDashboardService_UpdateDashboardACL_Call { + _c.Call.Return(run) + return _c +} + type mockConstructorTestingTNewFakeDashboardService interface { mock.TestingT Cleanup(func()) diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 4c2650452e6..1dd16df8d06 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" - "github.com/grafana/grafana/pkg/infra/appcontext" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/alerting" @@ -633,18 +632,13 @@ func (dr *DashboardServiceImpl) DeleteACLByUser(ctx context.Context, userID int6 return dr.dashboardStore.DeleteACLByUser(ctx, userID) } -func (dr DashboardServiceImpl) CountDashboardsInFolder(ctx context.Context, query *dashboards.CountDashboardsInFolderQuery) (int64, error) { - u, err := appcontext.User(ctx) +func (dr DashboardServiceImpl) CountInFolder(ctx context.Context, orgID int64, uid string, u *user.SignedInUser) (int64, error) { + folder, err := dr.folderService.Get(ctx, &folder.GetFolderQuery{UID: &uid, OrgID: orgID, SignedInUser: u}) if err != nil { return 0, err } - folder, err := dr.folderService.Get(ctx, &folder.GetFolderQuery{UID: &query.FolderUID, OrgID: u.OrgID, SignedInUser: u}) - if err != nil { - return 0, err - } - - return dr.dashboardStore.CountDashboardsInFolder(ctx, &dashboards.CountDashboardsInFolderRequest{FolderID: folder.ID, OrgID: u.OrgID}) + return dr.dashboardStore.CountDashboardsInFolder(ctx, &dashboards.CountDashboardsInFolderRequest{FolderID: folder.ID, OrgID: orgID}) } func (dr *DashboardServiceImpl) DeleteInFolder(ctx context.Context, orgID int64, UID string) error { diff --git a/pkg/services/dashboards/service/dashboard_service_test.go b/pkg/services/dashboards/service/dashboard_service_test.go index 50774fd5727..6c435914484 100644 --- a/pkg/services/dashboards/service/dashboard_service_test.go +++ b/pkg/services/dashboards/service/dashboard_service_test.go @@ -236,7 +236,7 @@ func TestDashboardService(t *testing.T) { usr := &user.SignedInUser{UserID: 1} ctx := appcontext.WithUser(context.Background(), usr) - count, err := service.CountDashboardsInFolder(ctx, &dashboards.CountDashboardsInFolderQuery{FolderUID: "i am a folder"}) + count, err := service.CountInFolder(ctx, 1, "i am a folder", usr) require.NoError(t, err) require.Equal(t, int64(3), count) }) diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index c9d0d5d172b..cde1174ce9c 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -623,6 +623,28 @@ func (s *Service) nestedFolderDelete(ctx context.Context, cmd *folder.DeleteFold return result, nil } +func (s *Service) GetChildrenCounts(ctx context.Context, cmd *folder.GetChildrenCountsQuery) (folder.ChildrenCounts, error) { + if cmd.SignedInUser == nil { + return nil, folder.ErrBadRequest.Errorf("missing signed-in user") + } + if *cmd.UID == "" { + return nil, folder.ErrBadRequest.Errorf("missing UID") + } + if cmd.OrgID < 1 { + return nil, folder.ErrBadRequest.Errorf("invalid orgID") + } + + countsMap := make(folder.ChildrenCounts, len(s.registry)) + for _, v := range s.registry { + c, err := v.CountInFolder(ctx, cmd.OrgID, *cmd.UID, cmd.SignedInUser) + if err != nil { + return nil, err + } + countsMap[v.Kind()] += c + } + return countsMap, nil +} + // MakeUserAdmin is copy of DashboardServiceImpl.MakeUserAdmin func (s *Service) MakeUserAdmin(ctx context.Context, orgID int64, userID, folderID int64, setViewAndEditPermissions bool) error { rtEditor := org.RoleEditor diff --git a/pkg/services/folder/folderimpl/folder_test.go b/pkg/services/folder/folderimpl/folder_test.go index 77a123d1d56..323c45453a1 100644 --- a/pkg/services/folder/folderimpl/folder_test.go +++ b/pkg/services/folder/folderimpl/folder_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/infra/appcontext" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db/dbtest" "github.com/grafana/grafana/pkg/infra/log" @@ -22,6 +23,7 @@ import ( acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" + "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder/foldertest" @@ -930,6 +932,65 @@ func TestNestedFolderService(t *testing.T) { }) } +func TestGetChildrenCounts(t *testing.T) { + g := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true}) + t.Cleanup(func() { + guardian.New = g + }) + + folderId := rand.Int63() + folderUID := util.GenerateShortUID() + f := folder.NewFolder("Folder", "") + f.ID = folderId + f.UID = folderUID + f.OrgID = orgID + + nestedFolderStore := NewFakeStore() + nestedFolderStore.ExpectedFolder = f + + dashStore := dashboards.FakeDashboardStore{} + dashboardCount := int64(2) + countCmd := dashboards.CountDashboardsInFolderRequest{ + FolderID: f.ID, + OrgID: f.OrgID, + } + dashStore.On("CountDashboardsInFolder", mock.Anything, &countCmd).Return(dashboardCount, nil) + + dashboardFolderStore := foldertest.NewFakeFolderStore(t) + dashboardFolderStore.On("GetFolderByUID", mock.Anything, orgID, folderUID).Return(f, nil) + + cfg := setting.NewCfg() + cfg.RBACEnabled = false + features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders) + folderService := &Service{ + cfg: cfg, + store: nestedFolderStore, + dashboardStore: &dashStore, + dashboardFolderStore: dashboardFolderStore, + features: features, + log: log.New("test-folder-service"), + accessControl: acimpl.ProvideAccessControl(cfg), + registry: make(map[string]folder.RegistryService), + } + + ac := acmock.New() + folderPermissions := acmock.NewMockedPermissionsService() + dashboardPermissions := acmock.NewMockedPermissionsService() + _, err := service.ProvideDashboardServiceImpl(cfg, &dashStore, dashboardFolderStore, nil, features, folderPermissions, dashboardPermissions, ac, folderService) + require.NoError(t, err) + + signedInUser := user.SignedInUser{UserID: 1, OrgID: orgID} + ctx := appcontext.WithUser(context.Background(), &signedInUser) + res, err := folderService.GetChildrenCounts(ctx, &folder.GetChildrenCountsQuery{ + SignedInUser: usr, + UID: &folderUID, + OrgID: orgID, + }) + require.NoError(t, err) + require.Equal(t, res["dashboard"], dashboardCount) +} + func CreateSubtreeInStore(t *testing.T, store *sqlStore, service *Service, depth int, prefix string, cmd folder.CreateFolderCommand) []string { t.Helper() diff --git a/pkg/services/folder/foldertest/foldertest.go b/pkg/services/folder/foldertest/foldertest.go index 684cdf0bd6c..9468186147a 100644 --- a/pkg/services/folder/foldertest/foldertest.go +++ b/pkg/services/folder/foldertest/foldertest.go @@ -7,9 +7,10 @@ import ( ) type FakeService struct { - ExpectedFolders []*folder.Folder - ExpectedFolder *folder.Folder - ExpectedError error + ExpectedFolders []*folder.Folder + ExpectedFolder *folder.Folder + ExpectedError error + ExpectedChildrenCounts map[string]int64 } func NewFakeService() *FakeService { @@ -49,3 +50,7 @@ func (s *FakeService) Move(ctx context.Context, cmd *folder.MoveFolderCommand) ( func (s *FakeService) RegisterService(service folder.RegistryService) error { return s.ExpectedError } + +func (s *FakeService) GetChildrenCounts(ctx context.Context, cmd *folder.GetChildrenCountsQuery) (folder.ChildrenCounts, error) { + return s.ExpectedChildrenCounts, s.ExpectedError +} diff --git a/pkg/services/folder/model.go b/pkg/services/folder/model.go index a33caa7c100..87dbb54ae10 100644 --- a/pkg/services/folder/model.go +++ b/pkg/services/folder/model.go @@ -160,3 +160,14 @@ type HasEditPermissionInFoldersQuery struct { type HasAdminPermissionInDashboardsOrFoldersQuery struct { SignedInUser *user.SignedInUser } + +// GetChildrenCountsQuery captures the information required by the folder service +// to return the count of children in a folder. +type GetChildrenCountsQuery struct { + UID *string + OrgID int64 + + SignedInUser *user.SignedInUser `json:"-"` +} + +type ChildrenCounts map[string]int64 diff --git a/pkg/services/folder/registry.go b/pkg/services/folder/registry.go index 7aa088a38c9..0692957b9fd 100644 --- a/pkg/services/folder/registry.go +++ b/pkg/services/folder/registry.go @@ -2,9 +2,12 @@ package folder import ( "context" + + "github.com/grafana/grafana/pkg/services/user" ) type RegistryService interface { - DeleteInFolder(ctx context.Context, orgID int64, UID string) error + DeleteInFolder(ctx context.Context, orgID int64, uid string) error + CountInFolder(ctx context.Context, orgID int64, uid string, user *user.SignedInUser) (int64, error) Kind() string } diff --git a/pkg/services/folder/service.go b/pkg/services/folder/service.go index 06028c96783..720f9dd5eed 100644 --- a/pkg/services/folder/service.go +++ b/pkg/services/folder/service.go @@ -26,6 +26,7 @@ type Service interface { // Move changes a folder's parent folder to the requested new parent. Move(ctx context.Context, cmd *MoveFolderCommand) (*Folder, error) RegisterService(service RegistryService) error + GetChildrenCounts(ctx context.Context, cmd *GetChildrenCountsQuery) (ChildrenCounts, error) } // FolderStore is a folder store. diff --git a/public/api-merged.json b/public/api-merged.json index 82aeb49bfd7..a54985c3b32 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -5648,6 +5648,40 @@ } } }, + "/folders/{folder_uid}/counts": { + "get": { + "tags": [ + "folders" + ], + "summary": "Gets the count of each descendant of a folder by kind. The folder is identified by UID.", + "operationId": "getFolderChildrenCounts", + "parameters": [ + { + "type": "string", + "name": "folder_uid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getFolderChildrenCountsResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/folders/{folder_uid}/move": { "post": { "tags": [ @@ -13552,6 +13586,13 @@ } } }, + "FolderChildrenCounts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + }, "FolderSearchHit": { "type": "object", "properties": { @@ -20295,6 +20336,12 @@ "$ref": "#/definitions/DataSourceList" } }, + "getFolderChildrenCountsResponse": { + "description": "(empty)", + "schema": { + "$ref": "#/definitions/FolderChildrenCounts" + } + }, "getFolderPermissionListResponse": { "description": "(empty)", "schema": { diff --git a/public/openapi3.json b/public/openapi3.json index 814a35f50c3..c8243bc8671 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -792,6 +792,16 @@ }, "description": "(empty)" }, + "getFolderChildrenCountsResponse": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FolderChildrenCounts" + } + } + }, + "description": "(empty)" + }, "getFolderPermissionListResponse": { "content": { "application/json": { @@ -4644,6 +4654,13 @@ }, "type": "object" }, + "FolderChildrenCounts": { + "additionalProperties": { + "format": "int64", + "type": "integer" + }, + "type": "object" + }, "FolderSearchHit": { "properties": { "accessControl": { @@ -17002,6 +17019,42 @@ ] } }, + "/folders/{folder_uid}/counts": { + "get": { + "operationId": "getFolderChildrenCounts", + "parameters": [ + { + "in": "path", + "name": "folder_uid", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/getFolderChildrenCountsResponse" + }, + "401": { + "$ref": "#/components/responses/unauthorisedError" + }, + "403": { + "$ref": "#/components/responses/forbiddenError" + }, + "404": { + "$ref": "#/components/responses/notFoundError" + }, + "500": { + "$ref": "#/components/responses/internalServerError" + } + }, + "summary": "Gets the count of each descendant of a folder by kind. The folder is identified by UID.", + "tags": [ + "folders" + ] + } + }, "/folders/{folder_uid}/move": { "post": { "operationId": "moveFolder",