API: Support creating a nested folder (#58508)

* API: Support nested folder creation

* Update swagger

* fixup

* Update pkg/api/dtos/folder.go

Co-authored-by: Serge Zaitsev <serge.zaitsev@grafana.com>

* Fix some tests

* create legacy folder url from title and uid

Co-authored-by: idafurjes <36131195+idafurjes@users.noreply.github.com>
Co-authored-by: Serge Zaitsev <serge.zaitsev@grafana.com>
Co-authored-by: Ida Furjesova <ida.furjesova@grafana.com>
This commit is contained in:
Sofia Papagiannaki
2022-11-10 11:41:03 +02:00
committed by GitHub
parent b5388bb080
commit bf5a08e039
21 changed files with 452 additions and 137 deletions

View File

@@ -524,11 +524,11 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and folderFilter is set to existing folders, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) {
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel2")
command := getCreatePanelCommand(newFolder.ID, "Text - Library Panel2")
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
folderFilter := strconv.FormatInt(newFolder.Id, 10)
folderFilter := strconv.FormatInt(newFolder.ID, 10)
err := sc.reqContext.Req.ParseForm()
require.NoError(t, err)
@@ -548,7 +548,7 @@ func TestGetAllLibraryElements(t *testing.T) {
{
ID: 2,
OrgID: 1,
FolderID: newFolder.Id,
FolderID: newFolder.ID,
UID: result.Result.Elements[0].UID,
Name: "Text - Library Panel2",
Kind: int64(models.PanelElement),
@@ -564,7 +564,7 @@ func TestGetAllLibraryElements(t *testing.T) {
Version: 1,
Meta: LibraryElementDTOMeta{
FolderName: "NewFolder",
FolderUID: newFolder.Uid,
FolderUID: newFolder.UID,
ConnectedDashboards: 0,
Created: result.Result.Elements[0].Meta.Created,
Updated: result.Result.Elements[0].Meta.Updated,
@@ -591,7 +591,7 @@ func TestGetAllLibraryElements(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and folderFilter is set to a nonexistent folders, it should succeed and the result should be correct",
func(t *testing.T, sc scenarioContext) {
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel2")
command := getCreatePanelCommand(newFolder.ID, "Text - Library Panel2")
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())

View File

@@ -25,7 +25,7 @@ func TestPatchLibraryElement(t *testing.T) {
func(t *testing.T, sc scenarioContext) {
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
cmd := PatchLibraryElementCommand{
FolderID: newFolder.Id,
FolderID: newFolder.ID,
Name: "Panel - New name",
Model: []byte(`
{
@@ -48,7 +48,7 @@ func TestPatchLibraryElement(t *testing.T) {
Result: libraryElement{
ID: 1,
OrgID: 1,
FolderID: newFolder.Id,
FolderID: newFolder.ID,
UID: sc.initialResult.Result.UID,
Name: "Panel - New name",
Kind: int64(models.PanelElement),
@@ -90,7 +90,7 @@ func TestPatchLibraryElement(t *testing.T) {
func(t *testing.T, sc scenarioContext) {
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
cmd := PatchLibraryElementCommand{
FolderID: newFolder.Id,
FolderID: newFolder.ID,
Kind: int64(models.PanelElement),
Version: 1,
}
@@ -99,7 +99,7 @@ func TestPatchLibraryElement(t *testing.T) {
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.FolderID = newFolder.Id
sc.initialResult.Result.FolderID = newFolder.ID
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
sc.initialResult.Result.Meta.CreatedBy.AvatarURL = userInDbAvatar
sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated
@@ -325,7 +325,7 @@ func TestPatchLibraryElement(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to patch a library panel with a folder where a library panel with the same name already exists, it should fail",
func(t *testing.T, sc scenarioContext) {
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
command := getCreatePanelCommand(newFolder.Id, "Text - Library Panel")
command := getCreatePanelCommand(newFolder.ID, "Text - Library Panel")
sc.ctx.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp)

View File

@@ -73,7 +73,7 @@ func TestLibraryElementPermissions(t *testing.T) {
folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, testCase.items)
sc.reqContext.SignedInUser.OrgRole = testCase.role
command := getCreatePanelCommand(folder.Id, "Library Panel Name")
command := getCreatePanelCommand(folder.ID, "Library Panel Name")
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, testCase.status, resp.Status())
@@ -82,14 +82,14 @@ func TestLibraryElementPermissions(t *testing.T) {
testScenario(t, fmt.Sprintf("When %s tries to patch a library panel by moving it to a folder with %s, it should return correct status", testCase.role, testCase.desc),
func(t *testing.T, sc scenarioContext) {
fromFolder := createFolderWithACL(t, sc.sqlStore, "Everyone", sc.user, everyonePermissions)
command := getCreatePanelCommand(fromFolder.Id, "Library Panel Name")
command := getCreatePanelCommand(fromFolder.ID, "Library Panel Name")
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp)
toFolder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, testCase.items)
sc.reqContext.SignedInUser.OrgRole = testCase.role
cmd := PatchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(models.PanelElement)}
cmd := PatchLibraryElementCommand{FolderID: toFolder.ID, Version: 1, Kind: int64(models.PanelElement)}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
sc.reqContext.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
@@ -99,14 +99,14 @@ func TestLibraryElementPermissions(t *testing.T) {
testScenario(t, fmt.Sprintf("When %s tries to patch a library panel by moving it from a folder with %s, it should return correct status", testCase.role, testCase.desc),
func(t *testing.T, sc scenarioContext) {
fromFolder := createFolderWithACL(t, sc.sqlStore, "Everyone", sc.user, testCase.items)
command := getCreatePanelCommand(fromFolder.Id, "Library Panel Name")
command := getCreatePanelCommand(fromFolder.ID, "Library Panel Name")
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp)
toFolder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions)
sc.reqContext.SignedInUser.OrgRole = testCase.role
cmd := PatchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(models.PanelElement)}
cmd := PatchLibraryElementCommand{FolderID: toFolder.ID, Version: 1, Kind: int64(models.PanelElement)}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
sc.reqContext.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
@@ -116,7 +116,7 @@ func TestLibraryElementPermissions(t *testing.T) {
testScenario(t, fmt.Sprintf("When %s tries to delete a library panel in a folder with %s, it should return correct status", testCase.role, testCase.desc),
func(t *testing.T, sc scenarioContext) {
folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, testCase.items)
cmd := getCreatePanelCommand(folder.Id, "Library Panel Name")
cmd := getCreatePanelCommand(folder.ID, "Library Panel Name")
sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp)
@@ -151,7 +151,7 @@ func TestLibraryElementPermissions(t *testing.T) {
testScenario(t, fmt.Sprintf("When %s tries to patch a library panel by moving it to the General folder, it should return correct status", testCase.role),
func(t *testing.T, sc scenarioContext) {
folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions)
command := getCreatePanelCommand(folder.Id, "Library Panel Name")
command := getCreatePanelCommand(folder.ID, "Library Panel Name")
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp)
@@ -173,7 +173,7 @@ func TestLibraryElementPermissions(t *testing.T) {
result := validateAndUnMarshalResponse(t, resp)
sc.reqContext.SignedInUser.OrgRole = testCase.role
cmd := PatchLibraryElementCommand{FolderID: folder.Id, Version: 1, Kind: int64(models.PanelElement)}
cmd := PatchLibraryElementCommand{FolderID: folder.ID, Version: 1, Kind: int64(models.PanelElement)}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
@@ -216,7 +216,7 @@ func TestLibraryElementPermissions(t *testing.T) {
testScenario(t, fmt.Sprintf("When %s tries to patch a library panel by moving it to a folder that doesn't exist, it should fail", testCase.role),
func(t *testing.T, sc scenarioContext) {
folder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions)
command := getCreatePanelCommand(folder.Id, "Library Panel Name")
command := getCreatePanelCommand(folder.ID, "Library Panel Name")
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp)
@@ -245,7 +245,7 @@ func TestLibraryElementPermissions(t *testing.T) {
var results []libraryElement
for i, folderCase := range folderCases {
folder := createFolderWithACL(t, sc.sqlStore, fmt.Sprintf("Folder%v", i), sc.user, folderCase)
cmd := getCreatePanelCommand(folder.Id, fmt.Sprintf("Library Panel in Folder%v", i))
cmd := getCreatePanelCommand(folder.ID, fmt.Sprintf("Library Panel in Folder%v", i))
sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp)
@@ -254,7 +254,7 @@ func TestLibraryElementPermissions(t *testing.T) {
result.Result.Meta.UpdatedBy.Name = userInDbName
result.Result.Meta.UpdatedBy.AvatarURL = userInDbAvatar
result.Result.Meta.FolderName = folder.Title
result.Result.Meta.FolderUID = folder.Uid
result.Result.Meta.FolderUID = folder.UID
results = append(results, result.Result)
}
sc.reqContext.SignedInUser.OrgRole = testCase.role
@@ -308,7 +308,7 @@ func TestLibraryElementPermissions(t *testing.T) {
var results []libraryElement
for i, folderCase := range folderCases {
folder := createFolderWithACL(t, sc.sqlStore, fmt.Sprintf("Folder%v", i), sc.user, folderCase)
cmd := getCreatePanelCommand(folder.Id, fmt.Sprintf("Library Panel in Folder%v", i))
cmd := getCreatePanelCommand(folder.ID, fmt.Sprintf("Library Panel in Folder%v", i))
sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.createHandler(sc.reqContext)
result := validateAndUnMarshalResponse(t, resp)
@@ -317,7 +317,7 @@ func TestLibraryElementPermissions(t *testing.T) {
result.Result.Meta.UpdatedBy.Name = userInDbName
result.Result.Meta.UpdatedBy.AvatarURL = userInDbAvatar
result.Result.Meta.FolderName = folder.Title
result.Result.Meta.FolderUID = folder.Uid
result.Result.Meta.FolderUID = folder.UID
results = append(results, result.Result)
}
sc.reqContext.SignedInUser.OrgRole = testCase.role

View File

@@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"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/tracing"
@@ -25,6 +26,7 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "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/folderimpl"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
@@ -294,7 +296,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
}
func createFolderWithACL(t *testing.T, sqlStore db.DB, title string, user user.SignedInUser,
items []folderACLItem) *models.Folder {
items []folderACLItem) *folder.Folder {
t.Helper()
cfg := setting.NewCfg()
@@ -312,10 +314,13 @@ func createFolderWithACL(t *testing.T, sqlStore db.DB, title string, user user.S
)
s := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), cfg, d, dashboardStore, nil, features, folderPermissions, nil)
t.Logf("Creating folder with title and UID %q", title)
folder, err := s.CreateFolder(context.Background(), &user, user.OrgID, title, title)
ctx := appcontext.WithUser(context.Background(), &user)
folder, err := s.Create(ctx, &folder.CreateFolderCommand{
OrgID: user.OrgID, Title: title, UID: title,
})
require.NoError(t, err)
updateFolderACL(t, dashboardStore, folder.Id, items)
updateFolderACL(t, dashboardStore, folder.ID, items)
return folder
}
@@ -456,7 +461,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
},
}
sc.folder = createFolderWithACL(t, sc.sqlStore, "ScenarioFolder", sc.user, []folderACLItem{})
sc.folder = createFolderWithACL(t, sc.sqlStore, "ScenarioFolder", sc.user, []folderACLItem{}).ToLegacyModel()
fn(t, sc)
})