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>
This commit is contained in:
Arati R 2023-04-24 15:57:28 +02:00 committed by GitHub
parent 990b3c07ab
commit fd434cab58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 821 additions and 36 deletions

View File

@ -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))

View File

@ -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"`
}

View File

@ -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.

View File

@ -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())

View File

@ -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 {

View File

@ -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)
})

View File

@ -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

View File

@ -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()

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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.

View File

@ -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": {

View File

@ -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",