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 04:41:03 -05:00
committed by GitHub
co-authored by Serge Zaitsev idafurjes Ida Furjesova
parent b5388bb080
commit bf5a08e039
21 changed files with 452 additions and 137 deletions
+23 -25
View File
@@ -21,7 +21,6 @@ import (
"github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
type Service struct {
@@ -150,16 +149,21 @@ func (s *Service) GetFolderByTitle(ctx context.Context, user *user.SignedInUser,
return dashFolder, nil
}
func (s *Service) CreateFolder(ctx context.Context, user *user.SignedInUser, orgID int64, title, uid string) (*models.Folder, error) {
dashFolder := models.NewDashboardFolder(title)
dashFolder.OrgId = orgID
func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (*folder.Folder, error) {
dashFolder := models.NewDashboardFolder(cmd.Title)
dashFolder.OrgId = cmd.OrgID
trimmedUID := strings.TrimSpace(uid)
trimmedUID := strings.TrimSpace(cmd.UID)
if trimmedUID == accesscontrol.GeneralFolderUID {
return nil, dashboards.ErrFolderInvalidUID
}
dashFolder.SetUid(trimmedUID)
user, err := appcontext.User(ctx)
if err != nil {
return nil, err
}
userID := user.UserID
if userID == 0 {
userID = -1
@@ -170,7 +174,7 @@ func (s *Service) CreateFolder(ctx context.Context, user *user.SignedInUser, org
dto := &dashboards.SaveDashboardDTO{
Dashboard: dashFolder,
OrgId: orgID,
OrgId: cmd.OrgID,
User: user,
}
@@ -185,7 +189,7 @@ func (s *Service) CreateFolder(ctx context.Context, user *user.SignedInUser, org
}
var createdFolder *models.Folder
createdFolder, err = s.dashboardStore.GetFolderByID(ctx, orgID, dash.Id)
createdFolder, err = s.dashboardStore.GetFolderByID(ctx, cmd.OrgID, dash.Id)
if err != nil {
return nil, err
}
@@ -204,9 +208,9 @@ func (s *Service) CreateFolder(ctx context.Context, user *user.SignedInUser, org
{BuiltinRole: string(org.RoleViewer), Permission: models.PERMISSION_VIEW.String()},
}...)
_, permissionErr = s.permissions.SetPermissions(ctx, orgID, createdFolder.Uid, permissions...)
_, permissionErr = s.permissions.SetPermissions(ctx, cmd.OrgID, createdFolder.Uid, permissions...)
} else if s.cfg.EditorsCanAdmin && user.IsRealUser() && !user.IsAnonymous {
permissionErr = s.MakeUserAdmin(ctx, orgID, userID, createdFolder.Id, true)
permissionErr = s.MakeUserAdmin(ctx, cmd.OrgID, userID, createdFolder.Id, true)
}
if permissionErr != nil {
@@ -219,31 +223,34 @@ func (s *Service) CreateFolder(ctx context.Context, user *user.SignedInUser, org
description = dash.Data.Get("description").MustString()
}
parentUID := folder.RootFolderUID
if cmd.ParentUID != "" {
parentUID = cmd.ParentUID
}
_, err := s.store.Create(ctx, folder.CreateFolderCommand{
// TODO: Today, if a UID isn't specified, the dashboard store
// generates a new UID. The new folder store will need to do this as
// well, but for now we take the UID from the newly created folder.
UID: dash.Uid,
OrgID: orgID,
Title: title,
OrgID: cmd.OrgID,
Title: cmd.Title,
Description: description,
ParentUID: folder.RootFolderUID,
ParentUID: parentUID,
})
if err != nil {
// We'll log the error and also roll back the previously-created
// (legacy) folder.
s.log.Error("error saving folder to nested folder store", err)
err = s.DeleteFolder(ctx, &folder.DeleteFolderCommand{UID: createdFolder.Uid, OrgID: orgID, ForceDeleteRules: true})
err = s.DeleteFolder(ctx, &folder.DeleteFolderCommand{UID: createdFolder.Uid, OrgID: cmd.OrgID, ForceDeleteRules: true})
if err != nil {
s.log.Error("error deleting folder after failed save to nested folder store", err)
}
return createdFolder, err
return folder.FromDashboard(dash), err
}
// The folder UID is specified (or generated) during creation, so we'll
// stop here and return the created model.Folder.
}
return createdFolder, nil
return folder.FromDashboard(dash), nil
}
func (s *Service) UpdateFolder(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error {
@@ -333,15 +340,6 @@ func (s *Service) DeleteFolder(ctx context.Context, cmd *folder.DeleteFolderComm
return nil
}
func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (*folder.Folder, error) {
// check the flag, if old - do whatever did before
// for new only the store
if cmd.UID == "" {
cmd.UID = util.GenerateShortUID()
}
return s.store.Create(ctx, *cmd)
}
func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) (*folder.Folder, error) {
// check the flag, if old - do whatever did before
// for new only the store