2018-01-29 06:51:01 -06:00
|
|
|
package api
|
|
|
|
|
2018-02-20 11:11:50 -06:00
|
|
|
import (
|
2018-02-21 04:24:54 -06:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2022-06-22 03:29:26 -05:00
|
|
|
"net/http"
|
2023-03-20 06:04:22 -05:00
|
|
|
"strings"
|
2018-02-21 04:24:54 -06:00
|
|
|
"testing"
|
|
|
|
|
2022-06-30 08:31:54 -05:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2018-02-21 04:24:54 -06:00
|
|
|
"github.com/grafana/grafana/pkg/api/dtos"
|
2022-06-22 03:29:26 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
2022-11-24 08:38:55 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
2022-06-22 03:29:26 -05:00
|
|
|
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
2018-03-06 16:59:45 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
2022-03-03 08:05:47 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
2022-10-10 14:47:53 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/folder"
|
|
|
|
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
2022-07-15 11:06:44 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
2023-01-30 08:17:53 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/search/model"
|
2022-08-10 04:56:48 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/user"
|
2019-03-06 01:09:34 -06:00
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
2022-06-22 03:29:26 -05:00
|
|
|
"github.com/grafana/grafana/pkg/web/webtest"
|
2018-02-20 11:11:50 -06:00
|
|
|
)
|
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
func TestFoldersCreateAPIEndpoint(t *testing.T) {
|
2022-10-10 14:47:53 -05:00
|
|
|
folderService := &foldertest.FakeService{}
|
2023-03-20 06:04:22 -05:00
|
|
|
setUpRBACGuardian(t)
|
2022-02-16 07:15:44 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
folderWithoutParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\"}"
|
|
|
|
|
|
|
|
type testCase struct {
|
|
|
|
description string
|
|
|
|
expectedCode int
|
|
|
|
expectedFolder *folder.Folder
|
|
|
|
expectedFolderSvcError error
|
|
|
|
permissions []accesscontrol.Permission
|
|
|
|
withNestedFolders bool
|
|
|
|
input string
|
|
|
|
}
|
|
|
|
tcs := []testCase{
|
|
|
|
{
|
|
|
|
description: "folder creation succeeds given the correct request for creating a folder",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusOK,
|
|
|
|
expectedFolder: &folder.Folder{ID: 1, UID: "uid", Title: "Folder"},
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails without permissions to create a folder",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusForbidden,
|
|
|
|
permissions: []accesscontrol.Permission{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails given folder service error %s",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusConflict,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderWithSameUIDExists,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails given folder service error %s",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusBadRequest,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderTitleEmpty,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails given folder service error %s",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusBadRequest,
|
|
|
|
expectedFolderSvcError: dashboards.ErrDashboardInvalidUid,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails given folder service error %s",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusBadRequest,
|
|
|
|
expectedFolderSvcError: dashboards.ErrDashboardUidTooLong,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails given folder service error %s",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusConflict,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderSameNameExists,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails given folder service error %s",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusForbidden,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderAccessDenied,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails given folder service error %s",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusNotFound,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderNotFound,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder creation fails given folder service error %s",
|
|
|
|
input: folderWithoutParentInput,
|
|
|
|
expectedCode: http.StatusPreconditionFailed,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderVersionMismatch,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range tcs {
|
|
|
|
folderService.ExpectedFolder = tc.expectedFolder
|
|
|
|
folderService.ExpectedError = tc.expectedFolderSvcError
|
|
|
|
folderPermService := acmock.NewMockedPermissionsService()
|
|
|
|
folderPermService.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
|
|
|
|
|
|
|
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
|
|
|
hs.Cfg = &setting.Cfg{
|
|
|
|
RBACEnabled: true,
|
|
|
|
}
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
if tc.withNestedFolders {
|
|
|
|
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
|
|
|
|
}
|
|
|
|
hs.folderService = folderService
|
|
|
|
hs.folderPermissionsService = folderPermService
|
|
|
|
hs.accesscontrolService = actest.FakeService{}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run(testDescription(tc.description, tc.expectedFolderSvcError), func(t *testing.T) {
|
|
|
|
input := strings.NewReader(tc.input)
|
|
|
|
req := srv.NewPostRequest("/api/folders", input)
|
|
|
|
req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions))
|
|
|
|
resp, err := srv.SendJSON(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, tc.expectedCode, resp.StatusCode)
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
folder := dtos.Folder{}
|
|
|
|
err = json.NewDecoder(resp.Body).Decode(&folder)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, resp.Body.Close())
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
if tc.expectedCode == http.StatusOK {
|
2020-11-13 02:52:38 -06:00
|
|
|
assert.Equal(t, int64(1), folder.Id)
|
|
|
|
assert.Equal(t, "uid", folder.Uid)
|
|
|
|
assert.Equal(t, "Folder", folder.Title)
|
2023-03-20 06:04:22 -05:00
|
|
|
}
|
2022-10-10 14:47:53 -05:00
|
|
|
})
|
2023-03-20 06:04:22 -05:00
|
|
|
}
|
|
|
|
}
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
func TestFoldersUpdateAPIEndpoint(t *testing.T) {
|
|
|
|
folderService := &foldertest.FakeService{}
|
|
|
|
setUpRBACGuardian(t)
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
type testCase struct {
|
|
|
|
description string
|
|
|
|
expectedCode int
|
|
|
|
expectedFolder *folder.Folder
|
|
|
|
expectedFolderSvcError error
|
|
|
|
permissions []accesscontrol.Permission
|
|
|
|
}
|
|
|
|
tcs := []testCase{
|
|
|
|
{
|
|
|
|
description: "folder updating succeeds given the correct request and permissions to update a folder",
|
|
|
|
expectedCode: http.StatusOK,
|
|
|
|
expectedFolder: &folder.Folder{ID: 1, UID: "uid", Title: "Folder upd"},
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails without permissions to update a folder",
|
|
|
|
expectedCode: http.StatusForbidden,
|
|
|
|
permissions: []accesscontrol.Permission{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails given folder service error %s",
|
|
|
|
expectedCode: http.StatusConflict,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderWithSameUIDExists,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails given folder service error %s",
|
|
|
|
expectedCode: http.StatusBadRequest,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderTitleEmpty,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails given folder service error %s",
|
|
|
|
expectedCode: http.StatusBadRequest,
|
|
|
|
expectedFolderSvcError: dashboards.ErrDashboardInvalidUid,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails given folder service error %s",
|
|
|
|
expectedCode: http.StatusBadRequest,
|
|
|
|
expectedFolderSvcError: dashboards.ErrDashboardUidTooLong,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails given folder service error %s",
|
|
|
|
expectedCode: http.StatusConflict,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderSameNameExists,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails given folder service error %s",
|
|
|
|
expectedCode: http.StatusForbidden,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderAccessDenied,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails given folder service error %s",
|
|
|
|
expectedCode: http.StatusNotFound,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderNotFound,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "folder updating fails given folder service error %s",
|
|
|
|
expectedCode: http.StatusPreconditionFailed,
|
|
|
|
expectedFolderSvcError: dashboards.ErrFolderVersionMismatch,
|
|
|
|
permissions: []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range tcs {
|
|
|
|
folderService.ExpectedFolder = tc.expectedFolder
|
|
|
|
folderService.ExpectedError = tc.expectedFolderSvcError
|
|
|
|
|
|
|
|
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
|
|
|
hs.Cfg = &setting.Cfg{
|
|
|
|
RBACEnabled: true,
|
|
|
|
}
|
|
|
|
hs.folderService = folderService
|
|
|
|
})
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
t.Run(testDescription(tc.description, tc.expectedFolderSvcError), func(t *testing.T) {
|
|
|
|
input := strings.NewReader("{ \"uid\": \"uid\", \"title\": \"Folder upd\" }")
|
|
|
|
req := srv.NewRequest(http.MethodPut, "/api/folders/uid", input)
|
|
|
|
req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions))
|
|
|
|
resp, err := srv.SendJSON(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, tc.expectedCode, resp.StatusCode)
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
folder := dtos.Folder{}
|
|
|
|
err = json.NewDecoder(resp.Body).Decode(&folder)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, resp.Body.Close())
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
if tc.expectedCode == http.StatusOK {
|
2020-11-13 02:52:38 -06:00
|
|
|
assert.Equal(t, int64(1), folder.Id)
|
|
|
|
assert.Equal(t, "uid", folder.Uid)
|
|
|
|
assert.Equal(t, "Folder upd", folder.Title)
|
2023-03-20 06:04:22 -05:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-02-21 04:24:54 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
func testDescription(description string, expectedErr error) string {
|
|
|
|
if expectedErr != nil {
|
|
|
|
return fmt.Sprintf(description, expectedErr.Error())
|
|
|
|
} else {
|
|
|
|
return description
|
|
|
|
}
|
2018-02-21 04:24:54 -06:00
|
|
|
}
|
|
|
|
|
2022-06-22 03:29:26 -05:00
|
|
|
func TestHTTPServer_FolderMetadata(t *testing.T) {
|
|
|
|
setUpRBACGuardian(t)
|
2022-10-10 14:47:53 -05:00
|
|
|
folderService := &foldertest.FakeService{}
|
2023-04-21 09:05:11 -05:00
|
|
|
features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
|
2022-06-22 03:29:26 -05:00
|
|
|
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
2023-03-20 06:04:22 -05:00
|
|
|
hs.Cfg = &setting.Cfg{
|
|
|
|
RBACEnabled: true,
|
|
|
|
}
|
2022-06-22 03:29:26 -05:00
|
|
|
hs.folderService = folderService
|
2022-11-14 13:08:10 -06:00
|
|
|
hs.QuotaService = quotatest.New(false, nil)
|
2023-01-23 06:09:09 -06:00
|
|
|
hs.SearchService = &mockSearchService{
|
2023-01-30 08:17:53 -06:00
|
|
|
ExpectedResult: model.HitList{},
|
2023-01-23 06:09:09 -06:00
|
|
|
}
|
2023-04-21 09:05:11 -05:00
|
|
|
hs.Features = features
|
2022-06-22 03:29:26 -05:00
|
|
|
})
|
|
|
|
|
2023-04-21 09:05:11 -05:00
|
|
|
t.Run("Should attach access control metadata to folder response", func(t *testing.T) {
|
|
|
|
folderService.ExpectedFolder = &folder.Folder{UID: "folderUid"}
|
2022-06-22 03:29:26 -05:00
|
|
|
|
2023-04-21 09:05:11 -05:00
|
|
|
req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true")
|
2022-08-11 06:28:55 -05:00
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
2022-06-22 03:29:26 -05:00
|
|
|
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
|
|
|
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
|
2023-04-21 09:05:11 -05:00
|
|
|
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
|
2022-06-22 03:29:26 -05:00
|
|
|
}),
|
|
|
|
}})
|
|
|
|
|
|
|
|
res, err := server.Send(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
2023-04-21 09:05:11 -05:00
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
2022-06-22 03:29:26 -05:00
|
|
|
|
2023-04-21 09:05:11 -05:00
|
|
|
body := dtos.Folder{}
|
2022-06-22 03:29:26 -05:00
|
|
|
require.NoError(t, json.NewDecoder(res.Body).Decode(&body))
|
|
|
|
|
2023-04-21 09:05:11 -05:00
|
|
|
assert.True(t, body.AccessControl[dashboards.ActionFoldersRead])
|
|
|
|
assert.True(t, body.AccessControl[dashboards.ActionFoldersWrite])
|
2022-06-22 03:29:26 -05:00
|
|
|
})
|
|
|
|
|
2023-04-21 09:05:11 -05:00
|
|
|
t.Run("Should attach access control metadata to folder response with permissions cascading from nested folders", func(t *testing.T) {
|
2022-11-10 03:41:03 -06:00
|
|
|
folderService.ExpectedFolder = &folder.Folder{UID: "folderUid"}
|
2023-04-21 09:05:11 -05:00
|
|
|
folderService.ExpectedFolders = []*folder.Folder{{UID: "parentUid"}}
|
|
|
|
features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
|
|
|
|
defer func() {
|
|
|
|
features = featuremgmt.WithFeatures()
|
|
|
|
folderService.ExpectedFolders = nil
|
|
|
|
}()
|
2022-06-22 03:29:26 -05:00
|
|
|
|
|
|
|
req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true")
|
2022-08-11 06:28:55 -05:00
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
2022-06-22 03:29:26 -05:00
|
|
|
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
|
|
|
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
|
2023-04-21 09:05:11 -05:00
|
|
|
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("parentUid")},
|
|
|
|
{Action: dashboards.ActionDashboardsCreate, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
|
2022-06-22 03:29:26 -05:00
|
|
|
}),
|
|
|
|
}})
|
|
|
|
|
|
|
|
res, err := server.Send(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
|
|
|
|
body := dtos.Folder{}
|
|
|
|
require.NoError(t, json.NewDecoder(res.Body).Decode(&body))
|
|
|
|
|
|
|
|
assert.True(t, body.AccessControl[dashboards.ActionFoldersRead])
|
|
|
|
assert.True(t, body.AccessControl[dashboards.ActionFoldersWrite])
|
2023-04-21 09:05:11 -05:00
|
|
|
assert.True(t, body.AccessControl[dashboards.ActionDashboardsCreate])
|
2022-06-22 03:29:26 -05:00
|
|
|
})
|
|
|
|
|
2023-04-21 09:05:11 -05:00
|
|
|
t.Run("Should not attach access control metadata to folder response", func(t *testing.T) {
|
2022-11-10 03:41:03 -06:00
|
|
|
folderService.ExpectedFolder = &folder.Folder{UID: "folderUid"}
|
2022-06-22 03:29:26 -05:00
|
|
|
|
|
|
|
req := server.NewGetRequest("/api/folders/folderUid")
|
2022-08-11 06:28:55 -05:00
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
2022-06-22 03:29:26 -05:00
|
|
|
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
|
|
|
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
|
|
|
|
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
|
|
|
|
}),
|
|
|
|
}})
|
|
|
|
|
|
|
|
res, err := server.Send(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
|
|
|
|
body := dtos.Folder{}
|
|
|
|
require.NoError(t, json.NewDecoder(res.Body).Decode(&body))
|
|
|
|
|
|
|
|
assert.False(t, body.AccessControl[dashboards.ActionFoldersRead])
|
|
|
|
assert.False(t, body.AccessControl[dashboards.ActionFoldersWrite])
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
func TestFolderMoveAPIEndpoint(t *testing.T) {
|
2023-03-30 03:46:11 -05:00
|
|
|
folderService := &foldertest.FakeService{
|
|
|
|
ExpectedFolder: &folder.Folder{},
|
|
|
|
}
|
2022-06-22 03:29:26 -05:00
|
|
|
setUpRBACGuardian(t)
|
2019-03-06 01:09:34 -06:00
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
type testCase struct {
|
|
|
|
description string
|
|
|
|
expectedCode int
|
|
|
|
permissions []accesscontrol.Permission
|
|
|
|
newParentUid string
|
|
|
|
}
|
|
|
|
tcs := []testCase{
|
|
|
|
{
|
|
|
|
description: "can move folder to another folder with specific permissions",
|
|
|
|
newParentUid: "newParentUid",
|
|
|
|
expectedCode: http.StatusOK,
|
|
|
|
permissions: []accesscontrol.Permission{
|
|
|
|
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")},
|
|
|
|
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("newParentUid")},
|
|
|
|
},
|
|
|
|
},
|
2023-03-30 03:46:11 -05:00
|
|
|
{
|
|
|
|
description: "can move folder to the root folder with specific permissions",
|
|
|
|
newParentUid: "",
|
|
|
|
expectedCode: http.StatusOK,
|
|
|
|
permissions: []accesscontrol.Permission{
|
|
|
|
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")},
|
|
|
|
},
|
|
|
|
},
|
2023-03-20 06:04:22 -05:00
|
|
|
{
|
|
|
|
description: "forbidden to move folder to another folder without the write access on the folder being moved",
|
|
|
|
newParentUid: "newParentUid",
|
|
|
|
expectedCode: http.StatusForbidden,
|
|
|
|
permissions: []accesscontrol.Permission{
|
|
|
|
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("newParentUid")},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range tcs {
|
|
|
|
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
|
|
|
hs.Cfg = &setting.Cfg{
|
|
|
|
RBACEnabled: true,
|
|
|
|
}
|
|
|
|
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
|
|
|
|
hs.folderService = folderService
|
2018-02-21 04:24:54 -06:00
|
|
|
})
|
|
|
|
|
2023-03-20 06:04:22 -05:00
|
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
|
|
input := strings.NewReader(fmt.Sprintf("{ \"parentUid\": \"%s\"}", tc.newParentUid))
|
|
|
|
req := srv.NewRequest(http.MethodPost, "/api/folders/uid/move", input)
|
|
|
|
req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions))
|
|
|
|
resp, err := srv.SendJSON(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, tc.expectedCode, resp.StatusCode)
|
|
|
|
require.NoError(t, resp.Body.Close())
|
2018-02-21 04:24:54 -06:00
|
|
|
})
|
2023-03-20 06:04:22 -05:00
|
|
|
}
|
2018-02-21 04:24:54 -06:00
|
|
|
}
|
2023-04-25 03:22:20 -05:00
|
|
|
|
|
|
|
func TestFolderGetAPIEndpoint(t *testing.T) {
|
|
|
|
folderService := &foldertest.FakeService{
|
|
|
|
ExpectedFolder: &folder.Folder{
|
|
|
|
ID: 1,
|
|
|
|
UID: "uid",
|
|
|
|
Title: "uid title",
|
|
|
|
},
|
|
|
|
ExpectedFolders: []*folder.Folder{
|
|
|
|
{
|
|
|
|
UID: "parent",
|
|
|
|
Title: "parent title",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
UID: "subfolder",
|
|
|
|
Title: "subfolder title",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
setUpRBACGuardian(t)
|
|
|
|
|
|
|
|
type testCase struct {
|
|
|
|
description string
|
|
|
|
URL string
|
|
|
|
features *featuremgmt.FeatureManager
|
|
|
|
expectedCode int
|
|
|
|
expectedParentUIDs []string
|
|
|
|
expectedParentTitles []string
|
|
|
|
permissions []accesscontrol.Permission
|
|
|
|
}
|
|
|
|
tcs := []testCase{
|
|
|
|
{
|
|
|
|
description: "get folder by UID should return parent folders if nested folder are enabled",
|
|
|
|
URL: "/api/folders/uid",
|
|
|
|
expectedCode: http.StatusOK,
|
|
|
|
features: featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders),
|
|
|
|
expectedParentUIDs: []string{"parent", "subfolder"},
|
|
|
|
expectedParentTitles: []string{"parent title", "subfolder title"},
|
|
|
|
permissions: []accesscontrol.Permission{
|
|
|
|
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "get folder by UID should not return parent folders if nested folder are disabled",
|
|
|
|
URL: "/api/folders/uid",
|
|
|
|
expectedCode: http.StatusOK,
|
|
|
|
features: featuremgmt.WithFeatures(),
|
|
|
|
expectedParentUIDs: []string{},
|
|
|
|
expectedParentTitles: []string{},
|
|
|
|
permissions: []accesscontrol.Permission{
|
|
|
|
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range tcs {
|
|
|
|
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
|
|
|
hs.Cfg = &setting.Cfg{
|
|
|
|
RBACEnabled: true,
|
|
|
|
}
|
|
|
|
hs.Features = tc.features
|
|
|
|
hs.folderService = folderService
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
|
|
req := srv.NewGetRequest(tc.URL)
|
|
|
|
req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions))
|
|
|
|
resp, err := srv.Send(req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, tc.expectedCode, resp.StatusCode)
|
|
|
|
|
|
|
|
folder := dtos.Folder{}
|
|
|
|
err = json.NewDecoder(resp.Body).Decode(&folder)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, len(folder.Parents), len(tc.expectedParentUIDs))
|
|
|
|
require.Equal(t, len(folder.Parents), len(tc.expectedParentTitles))
|
|
|
|
|
|
|
|
for i := 0; i < len(tc.expectedParentUIDs); i++ {
|
|
|
|
assert.Equal(t, tc.expectedParentUIDs[i], folder.Parents[i].Uid)
|
|
|
|
assert.Equal(t, tc.expectedParentTitles[i], folder.Parents[i].Title)
|
|
|
|
}
|
|
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|