From b13b58ebf82add32d1aed0d4a5fc39ce4f227a97 Mon Sep 17 00:00:00 2001 From: ying-jeanne <74549700+ying-jeanne@users.noreply.github.com> Date: Thu, 10 Nov 2022 15:06:52 +0100 Subject: [PATCH] Add move endpoint into folder service (#58575) * add move endpoint * change signatures --- pkg/api/api.go | 1 + pkg/api/folder.go | 27 +++++++++++++++++++ pkg/models/folders.go | 4 +++ pkg/services/folder/folderimpl/folder.go | 3 --- pkg/services/folder/folderimpl/folder_test.go | 10 +++++-- pkg/services/folder/foldertest/foldertest.go | 4 +++ pkg/services/folder/service.go | 5 ++-- 7 files changed, 46 insertions(+), 8 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 5692a904322..eb2cb600c2f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -435,6 +435,7 @@ func (hs *HTTPServer) registerRoutes() { folderRoute.Group("/:uid", func(folderUidRoute routing.RouteRegister) { folderUidRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersRead, uidScope)), routing.Wrap(hs.GetFolderByUID)) 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.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) { diff --git a/pkg/api/folder.go b/pkg/api/folder.go index 4c88b523f34..4d4197e2d43 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/models" "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/services/guardian" "github.com/grafana/grafana/pkg/services/libraryelements" @@ -131,6 +132,32 @@ func (hs *HTTPServer) CreateFolder(c *models.ReqContext) response.Response { return response.JSON(http.StatusOK, hs.newToFolderDto(c, g, folder)) } +func (hs *HTTPServer) MoveFolder(c *models.ReqContext) response.Response { + if hs.Features.IsEnabled(featuremgmt.FlagNestedFolders) { + cmd := models.MoveFolderCommand{} + if err := web.Bind(c.Req, &cmd); err != nil { + return response.Error(http.StatusBadRequest, "bad request data", err) + } + var theFolder *folder.Folder + var err error + if cmd.ParentUID != nil { + moveCommand := folder.MoveFolderCommand{ + UID: web.Params(c.Req)[":uid"], + NewParentUID: *cmd.ParentUID, + OrgID: c.OrgID, + } + theFolder, err = hs.folderService.Move(c.Req.Context(), &moveCommand) + if err != nil { + return response.Error(http.StatusInternalServerError, "update folder uid failed", err) + } + } + return response.JSON(http.StatusOK, theFolder) + } + result := map[string]string{} + result["message"] = "To use this service, you need to activate nested folder feature." + return response.JSON(http.StatusNotFound, result) +} + // swagger:route PUT /folders/{folder_uid} folders updateFolder // // Update folder. diff --git a/pkg/models/folders.go b/pkg/models/folders.go index 056425cc4aa..64b348a34d0 100644 --- a/pkg/models/folders.go +++ b/pkg/models/folders.go @@ -79,6 +79,10 @@ type CreateFolderCommand struct { Result *Folder `json:"-"` } +type MoveFolderCommand struct { + ParentUID *string `json:"parentUid"` +} + type UpdateFolderCommand struct { Uid string `json:"uid"` Title string `json:"title"` diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index 7ab907d21be..0de6fcf031e 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -376,9 +376,6 @@ func (s *Service) DeleteFolder(ctx context.Context, cmd *folder.DeleteFolderComm } 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 - foldr, err := s.Get(ctx, &folder.GetFolderQuery{ UID: &cmd.UID, OrgID: cmd.OrgID, diff --git a/pkg/services/folder/folderimpl/folder_test.go b/pkg/services/folder/folderimpl/folder_test.go index 1fe6d5ec9b8..5b8a142ea90 100644 --- a/pkg/services/folder/folderimpl/folder_test.go +++ b/pkg/services/folder/folderimpl/folder_test.go @@ -516,6 +516,14 @@ func TestNestedFolderService(t *testing.T) { }) }) + t.Run("move, no error", func(t *testing.T) { + store.ExpectedError = nil + store.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"} + f, err := foldersvc.Move(ctx, &folder.MoveFolderCommand{UID: "myFolder", NewParentUID: "newFolder", OrgID: orgID}) + require.NoError(t, err) + require.NotNil(t, f) + }) + t.Run("delete with success", func(t *testing.T) { var actualCmd *models.DeleteDashboardCommand dashStore.On("DeleteDashboard", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { @@ -526,8 +534,6 @@ func TestNestedFolderService(t *testing.T) { g := guardian.New guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) - store.ExpectedError = nil - err := foldersvc.DeleteFolder(ctx, &folder.DeleteFolderCommand{UID: "myFolder", OrgID: orgID}) require.NoError(t, err) require.NotNil(t, actualCmd) diff --git a/pkg/services/folder/foldertest/foldertest.go b/pkg/services/folder/foldertest/foldertest.go index 4b87a3288b3..20c81534d78 100644 --- a/pkg/services/folder/foldertest/foldertest.go +++ b/pkg/services/folder/foldertest/foldertest.go @@ -45,6 +45,10 @@ func (s *FakeService) MakeUserAdmin(ctx context.Context, orgID int64, userID, fo return s.ExpectedError } +func (s *FakeService) Move(ctx context.Context, cmd *folder.MoveFolderCommand) (*folder.Folder, error) { + return s.ExpectedFolder, s.ExpectedError +} + func (s *FakeService) GetParents(ctx context.Context, orgID int64, folderUID string) ([]*folder.Folder, error) { return modelsToFolders(s.ExpectedFolders), s.ExpectedError } diff --git a/pkg/services/folder/service.go b/pkg/services/folder/service.go index a1e6c958004..d91ba445066 100644 --- a/pkg/services/folder/service.go +++ b/pkg/services/folder/service.go @@ -18,6 +18,8 @@ type Service interface { 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 + // Move changes a folder's parent folder to the requested new parent. + Move(ctx context.Context, cmd *MoveFolderCommand) (*Folder, error) } // NestedFolderService is the temporary interface definition for the folder @@ -29,9 +31,6 @@ type NestedFolderService interface { // Create creates a new folder. Create(ctx context.Context, cmd *CreateFolderCommand) (*Folder, error) - // Move changes a folder's parent folder to the requested new parent. - Move(ctx context.Context, cmd *MoveFolderCommand) (*Folder, error) - // Delete deletes a folder. This will return an error if there are any // dashboards in the folder. Delete(ctx context.Context, cmd *DeleteFolderCommand) (*Folder, error)