mirror of
https://github.com/grafana/grafana.git
synced 2024-11-27 03:11:01 -06:00
Folder: Add implementation for Update for nested folder (#58479)
* Add implementation for Update nested folder * Remove parent uid from Update * Fix update
This commit is contained in:
parent
bd6ac793a0
commit
30f0d66983
@ -151,12 +151,12 @@ func (hs *HTTPServer) UpdateFolder(c *models.ReqContext) response.Response {
|
||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
err := hs.folderService.UpdateFolder(c.Req.Context(), c.SignedInUser, c.OrgID, web.Params(c.Req)[":uid"], &cmd)
|
||||
result, err := hs.folderService.Update(c.Req.Context(), c.SignedInUser, c.OrgID, web.Params(c.Req)[":uid"], &cmd)
|
||||
if err != nil {
|
||||
return apierrors.ToFolderErrorResponse(err)
|
||||
}
|
||||
g := guardian.New(c.Req.Context(), cmd.Result.Id, c.OrgID, c.SignedInUser)
|
||||
return response.JSON(http.StatusOK, hs.toFolderDto(c, g, cmd.Result))
|
||||
g := guardian.New(c.Req.Context(), result.Id, c.OrgID, c.SignedInUser)
|
||||
return response.JSON(http.StatusOK, hs.toFolderDto(c, g, result))
|
||||
}
|
||||
|
||||
// swagger:route DELETE /folders/{folder_uid} folders deleteFolder
|
||||
|
@ -80,10 +80,11 @@ type CreateFolderCommand struct {
|
||||
}
|
||||
|
||||
type UpdateFolderCommand struct {
|
||||
Uid string `json:"uid"`
|
||||
Title string `json:"title"`
|
||||
Version int `json:"version"`
|
||||
Overwrite bool `json:"overwrite"`
|
||||
Uid string `json:"uid"`
|
||||
Title string `json:"title"`
|
||||
Version int `json:"version"`
|
||||
Description string `json:"description"`
|
||||
Overwrite bool `json:"overwrite"`
|
||||
|
||||
Result *Folder `json:"-"`
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
@ -253,17 +254,53 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (
|
||||
return folder.FromDashboard(dash), nil
|
||||
}
|
||||
|
||||
func (s *Service) UpdateFolder(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error {
|
||||
func (s *Service) Update(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) (*models.Folder, error) {
|
||||
foldr, err := s.legacyUpdate(ctx, user, orgID, existingUid, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.features.IsEnabled(featuremgmt.FlagNestedFolders) {
|
||||
if cmd.Uid != "" {
|
||||
if !util.IsValidShortUID(cmd.Uid) {
|
||||
return nil, dashboards.ErrDashboardInvalidUid
|
||||
} else if util.IsShortUIDTooLong(cmd.Uid) {
|
||||
return nil, dashboards.ErrDashboardUidTooLong
|
||||
}
|
||||
}
|
||||
|
||||
getFolder, err := s.store.Get(ctx, folder.GetFolderQuery{
|
||||
UID: &existingUid,
|
||||
OrgID: orgID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = s.store.Update(ctx, folder.UpdateFolderCommand{
|
||||
Folder: getFolder,
|
||||
NewUID: &cmd.Uid,
|
||||
NewTitle: &cmd.Title,
|
||||
NewDescription: &cmd.Description,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return foldr, nil
|
||||
}
|
||||
|
||||
func (s *Service) legacyUpdate(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) (*models.Folder, error) {
|
||||
query := models.GetDashboardQuery{OrgId: orgID, Uid: existingUid}
|
||||
if _, err := s.dashboardStore.GetDashboard(ctx, &query); err != nil {
|
||||
return toFolderError(err)
|
||||
_, err := s.dashboardStore.GetDashboard(ctx, &query)
|
||||
if err != nil {
|
||||
return nil, toFolderError(err)
|
||||
}
|
||||
|
||||
dashFolder := query.Result
|
||||
currentTitle := dashFolder.Title
|
||||
|
||||
if !dashFolder.IsFolder {
|
||||
return dashboards.ErrFolderNotFound
|
||||
return nil, dashboards.ErrFolderNotFound
|
||||
}
|
||||
|
||||
cmd.UpdateDashboardModel(dashFolder, orgID, user.UserID)
|
||||
@ -277,34 +314,32 @@ func (s *Service) UpdateFolder(ctx context.Context, user *user.SignedInUser, org
|
||||
|
||||
saveDashboardCmd, err := s.dashboardService.BuildSaveDashboardCommand(ctx, dto, false, false)
|
||||
if err != nil {
|
||||
return toFolderError(err)
|
||||
return nil, toFolderError(err)
|
||||
}
|
||||
|
||||
dash, err := s.dashboardStore.SaveDashboard(ctx, *saveDashboardCmd)
|
||||
if err != nil {
|
||||
return toFolderError(err)
|
||||
return nil, toFolderError(err)
|
||||
}
|
||||
|
||||
var folder *models.Folder
|
||||
folder, err = s.dashboardStore.GetFolderByID(ctx, orgID, dash.Id)
|
||||
var foldr *models.Folder
|
||||
foldr, err = s.dashboardStore.GetFolderByID(ctx, orgID, dash.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
cmd.Result = folder
|
||||
|
||||
if currentTitle != folder.Title {
|
||||
if currentTitle != foldr.Title {
|
||||
if err := s.bus.Publish(ctx, &events.FolderTitleUpdated{
|
||||
Timestamp: folder.Updated,
|
||||
Title: folder.Title,
|
||||
Timestamp: foldr.Updated,
|
||||
Title: foldr.Title,
|
||||
ID: dash.Id,
|
||||
UID: dash.Uid,
|
||||
OrgID: orgID,
|
||||
}); err != nil {
|
||||
s.log.Error("failed to publish FolderTitleUpdated event", "folder", folder.Title, "user", user.UserID, "error", err)
|
||||
s.log.Error("failed to publish FolderTitleUpdated event", "folder", foldr.Title, "user", user.UserID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return foldr, nil
|
||||
}
|
||||
|
||||
func (s *Service) DeleteFolder(ctx context.Context, cmd *folder.DeleteFolderCommand) error {
|
||||
@ -340,12 +375,6 @@ func (s *Service) DeleteFolder(ctx context.Context, cmd *folder.DeleteFolderComm
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
return s.store.Update(ctx, *cmd)
|
||||
}
|
||||
|
||||
func (s *Service) Move(ctx context.Context, cmd *folder.MoveFolderCommand) (*folder.Folder, error) {
|
||||
// check the flag, if old - do whatever did before
|
||||
// for new only the store
|
||||
@ -359,8 +388,8 @@ func (s *Service) Move(ctx context.Context, cmd *folder.MoveFolderCommand) (*fol
|
||||
}
|
||||
|
||||
return s.store.Update(ctx, folder.UpdateFolderCommand{
|
||||
Folder: foldr,
|
||||
NewParentUID: &cmd.NewParentUID,
|
||||
Folder: foldr,
|
||||
// NewParentUID: &cmd.NewParentUID,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ func TestIntegrationFolderService(t *testing.T) {
|
||||
folder.Result = models.NewDashboard("dashboard-test")
|
||||
folder.Result.IsFolder = true
|
||||
}).Return(&models.Dashboard{}, nil)
|
||||
err := service.UpdateFolder(context.Background(), usr, orgID, folderUID, &models.UpdateFolderCommand{
|
||||
_, err := service.Update(context.Background(), usr, orgID, folderUID, &models.UpdateFolderCommand{
|
||||
Uid: folderUID,
|
||||
Title: "Folder-TEST",
|
||||
})
|
||||
@ -201,9 +201,9 @@ func TestIntegrationFolderService(t *testing.T) {
|
||||
Title: "TEST-Folder",
|
||||
}
|
||||
|
||||
err := service.UpdateFolder(context.Background(), usr, orgID, dashboardFolder.Uid, req)
|
||||
reqResult, err := service.Update(context.Background(), usr, orgID, dashboardFolder.Uid, req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, f, req.Result)
|
||||
require.Equal(t, f, reqResult)
|
||||
})
|
||||
|
||||
t.Run("When deleting folder by uid should not return access denied error", func(t *testing.T) {
|
||||
@ -338,12 +338,6 @@ func TestNestedFolderServiceFeatureToggle(t *testing.T) {
|
||||
require.NotNil(t, res.UID)
|
||||
})
|
||||
|
||||
t.Run("update folder", func(t *testing.T) {
|
||||
folderStore.ExpectedFolder = &folder.Folder{}
|
||||
_, err := folderService.Update(context.Background(), &folder.UpdateFolderCommand{})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("delete folder", func(t *testing.T) {
|
||||
folderStore.ExpectedFolder = &folder.Folder{}
|
||||
err := folderService.Delete(context.Background(), &folder.DeleteFolderCommand{})
|
||||
|
@ -122,12 +122,6 @@ func (ss *sqlStore) Update(ctx context.Context, cmd folder.UpdateFolderCommand)
|
||||
args = append(args, cmd.Folder.UID)
|
||||
}
|
||||
|
||||
if cmd.NewParentUID != nil {
|
||||
columnsToUpdate = append(columnsToUpdate, "parent_uid = ?")
|
||||
cmd.Folder.ParentUID = *cmd.NewParentUID
|
||||
args = append(args, cmd.Folder.UID)
|
||||
}
|
||||
|
||||
if len(columnsToUpdate) == 0 {
|
||||
return folder.ErrBadRequest.Errorf("no columns to update")
|
||||
}
|
||||
|
@ -34,9 +34,9 @@ func (s *FakeService) GetFolderByTitle(ctx context.Context, user *user.SignedInU
|
||||
func (s *FakeService) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (*folder.Folder, error) {
|
||||
return s.ExpectedFolder, s.ExpectedError
|
||||
}
|
||||
func (s *FakeService) UpdateFolder(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error {
|
||||
func (s *FakeService) Update(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) (*models.Folder, error) {
|
||||
cmd.Result = s.ExpectedFolder.ToLegacyModel()
|
||||
return s.ExpectedError
|
||||
return s.ExpectedFolder.ToLegacyModel(), s.ExpectedError
|
||||
}
|
||||
func (s *FakeService) DeleteFolder(ctx context.Context, cmd *folder.DeleteFolderCommand) error {
|
||||
return s.ExpectedError
|
||||
|
@ -73,7 +73,6 @@ type CreateFolderCommand struct {
|
||||
type UpdateFolderCommand struct {
|
||||
Folder *Folder `json:"folder"` // The extant folder
|
||||
NewUID *string `json:"uid" xorm:"uid"`
|
||||
NewParentUID *string `json:"parent_uid" xorm:"parent_uid"`
|
||||
NewTitle *string `json:"title"`
|
||||
NewDescription *string `json:"description"`
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ type Service interface {
|
||||
GetFolderByUID(ctx context.Context, user *user.SignedInUser, orgID int64, uid string) (*models.Folder, error)
|
||||
GetFolderByTitle(ctx context.Context, user *user.SignedInUser, orgID int64, title string) (*models.Folder, error)
|
||||
Create(ctx context.Context, cmd *CreateFolderCommand) (*Folder, error)
|
||||
UpdateFolder(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error
|
||||
// Update is used to update a folder's UID, Title and Description. To change
|
||||
// a folder's parent folder, use Move.
|
||||
Update(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) (*models.Folder, error)
|
||||
DeleteFolder(ctx context.Context, cmd *DeleteFolderCommand) error
|
||||
MakeUserAdmin(ctx context.Context, orgID int64, userID, folderID int64, setViewAndEditPermissions bool) error
|
||||
}
|
||||
@ -27,10 +29,6 @@ type NestedFolderService interface {
|
||||
// Create creates a new folder.
|
||||
Create(ctx context.Context, cmd *CreateFolderCommand) (*Folder, error)
|
||||
|
||||
// Update is used to update a folder's UID, Title and Description. To change
|
||||
// a folder's parent folder, use Move.
|
||||
Update(ctx context.Context, cmd *UpdateFolderCommand) (*Folder, error)
|
||||
|
||||
// Move changes a folder's parent folder to the requested new parent.
|
||||
Move(ctx context.Context, cmd *MoveFolderCommand) (*Folder, error)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user