From af2f51f196829e05084080d23c939dcbd9f50670 Mon Sep 17 00:00:00 2001 From: idafurjes <36131195+idafurjes@users.noreply.github.com> Date: Tue, 8 Nov 2022 11:33:13 +0100 Subject: [PATCH] Folder: Add folder service implementation (#58182) * Folder: Add folder service implementation * Add Move * Add tests * Add new servie method and adjust Update, Delete and Move * Remove contains * GetTree return children of depth one --- pkg/services/folder/folderimpl/folder.go | 73 +++++++++++++++++++ pkg/services/folder/folderimpl/folder_test.go | 67 +++++++++++++++++ pkg/services/folder/folderimpl/sqlstore.go | 6 ++ pkg/services/folder/folderimpl/store_fake.go | 8 +- pkg/services/folder/model.go | 5 +- pkg/services/folder/service.go | 2 +- 6 files changed, 157 insertions(+), 4 deletions(-) diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index e94983e8de9..019164504a4 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -18,9 +18,12 @@ 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 { + store store + log log.Logger cfg *setting.Cfg dashboardService dashboards.DashboardService @@ -284,6 +287,76 @@ func (s *Service) DeleteFolder(ctx context.Context, user *user.SignedInUser, org return dashFolder, 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 + 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 + + foldr, err := s.Get(ctx, &folder.GetFolderQuery{ + UID: &cmd.UID, + OrgID: cmd.OrgID, + }) + if err != nil { + return nil, err + } + + return s.store.Update(ctx, folder.UpdateFolderCommand{ + Folder: foldr, + NewParentUID: &cmd.NewParentUID, + }) +} + +func (s *Service) Delete(ctx context.Context, cmd *folder.DeleteFolderCommand) (*folder.Folder, error) { + // check the flag, if old - do whatever did before + // for new only the store + // check if dashboard exists + + foldr, err := s.Get(ctx, &folder.GetFolderQuery{ + UID: &cmd.UID, + OrgID: cmd.OrgID, + }) + if err != nil { + return nil, err + } + err = s.store.Delete(ctx, cmd.UID, cmd.OrgID) + if err != nil { + return nil, err + } + return foldr, nil +} + +func (s *Service) Get(ctx context.Context, cmd *folder.GetFolderQuery) (*folder.Folder, error) { + // check the flag, if old - do whatever did before + // for new only the store + return s.store.Get(ctx, *cmd) +} + +func (s *Service) GetParents(ctx context.Context, cmd *folder.GetParentsQuery) ([]*folder.Folder, error) { + // check the flag, if old - do whatever did before + // for new only the store + return s.store.GetParents(ctx, *cmd) +} + +func (s *Service) GetTree(ctx context.Context, cmd *folder.GetTreeQuery) ([]*folder.Folder, error) { + // check the flag, if old - do whatever did before + // for new only the store + return s.store.GetChildren(ctx, *cmd) +} + func (s *Service) MakeUserAdmin(ctx context.Context, orgID int64, userID, folderID int64, setViewAndEditPermissions bool) error { return s.dashboardService.MakeUserAdmin(ctx, orgID, userID, folderID, setViewAndEditPermissions) } diff --git a/pkg/services/folder/folderimpl/folder_test.go b/pkg/services/folder/folderimpl/folder_test.go index 7cb51195980..07a36ca9a7a 100644 --- a/pkg/services/folder/folderimpl/folder_test.go +++ b/pkg/services/folder/folderimpl/folder_test.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" dashboardsvc "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/guardian" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" @@ -259,3 +260,69 @@ func TestIntegrationFolderService(t *testing.T) { }) }) } + +func TestFolderService(t *testing.T) { + folderStore := NewFakeStore() + folderService := &Service{ + store: folderStore, + } + t.Run("create folder", func(t *testing.T) { + folderStore.ExpectedFolder = &folder.Folder{} + res, err := folderService.Create(context.Background(), &folder.CreateFolderCommand{}) + require.NoError(t, err) + 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{}) + require.NoError(t, err) + }) + + t.Run("get folder", func(t *testing.T) { + folderStore.ExpectedFolder = &folder.Folder{} + _, err := folderService.Get(context.Background(), &folder.GetFolderQuery{}) + require.NoError(t, err) + }) + + t.Run("get parents folder", func(t *testing.T) { + folderStore.ExpectedFolder = &folder.Folder{} + _, err := folderService.GetParents(context.Background(), &folder.GetParentsQuery{}) + require.NoError(t, err) + }) + + t.Run("get children folder", func(t *testing.T) { + folderStore.ExpectedFolders = []*folder.Folder{ + { + UID: "test", + }, + { + UID: "test2", + }, + { + UID: "test3", + }, + { + UID: "test4", + }, + } + res, err := folderService.GetTree(context.Background(), + &folder.GetTreeQuery{ + UID: "test", + }) + require.NoError(t, err) + require.Equal(t, 4, len(res)) + }) + + t.Run("move folder", func(t *testing.T) { + folderStore.ExpectedFolder = &folder.Folder{} + _, err := folderService.Move(context.Background(), &folder.MoveFolderCommand{}) + require.NoError(t, err) + }) +} diff --git a/pkg/services/folder/folderimpl/sqlstore.go b/pkg/services/folder/folderimpl/sqlstore.go index 52a2a6ffbde..5840bbba91c 100644 --- a/pkg/services/folder/folderimpl/sqlstore.go +++ b/pkg/services/folder/folderimpl/sqlstore.go @@ -120,6 +120,12 @@ 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") } diff --git a/pkg/services/folder/folderimpl/store_fake.go b/pkg/services/folder/folderimpl/store_fake.go index e74c23784de..302acda3e24 100644 --- a/pkg/services/folder/folderimpl/store_fake.go +++ b/pkg/services/folder/folderimpl/store_fake.go @@ -12,6 +12,10 @@ type FakeStore struct { ExpectedError error } +func NewFakeStore() *FakeStore { + return &FakeStore{} +} + var _ store = (*FakeStore)(nil) func (f *FakeStore) Create(ctx context.Context, cmd folder.CreateFolderCommand) (*folder.Folder, error) { @@ -26,8 +30,8 @@ func (f *FakeStore) Update(ctx context.Context, cmd folder.UpdateFolderCommand) return f.ExpectedFolder, f.ExpectedError } -func (f *FakeStore) Move(ctx context.Context, cmd folder.MoveFolderCommand) (*folder.Folder, error) { - return f.ExpectedFolder, f.ExpectedError +func (f *FakeStore) Move(ctx context.Context, cmd folder.MoveFolderCommand) error { + return f.ExpectedError } func (f *FakeStore) Get(ctx context.Context, cmd folder.GetFolderQuery) (*folder.Folder, error) { diff --git a/pkg/services/folder/model.go b/pkg/services/folder/model.go index e6f0a963010..3886b8471f4 100644 --- a/pkg/services/folder/model.go +++ b/pkg/services/folder/model.go @@ -60,6 +60,7 @@ 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"` } @@ -69,12 +70,14 @@ type UpdateFolderCommand struct { type MoveFolderCommand struct { UID string `json:"uid"` NewParentUID string `json:"new_parent_uid"` + OrgID int64 `json:"orgId"` } // DeleteFolderCommand captures the information required by the folder service // to delete a folder. type DeleteFolderCommand struct { - UID string `json:"uid" xorm:"uid"` + UID string `json:"uid" xorm:"uid"` + OrgID int64 `json:"orgId" xorm:"org_id"` } // GetFolderQuery is used for all folder Get requests. Only one of UID, ID, or diff --git a/pkg/services/folder/service.go b/pkg/services/folder/service.go index 49904dd3c04..1d18ea17890 100644 --- a/pkg/services/folder/service.go +++ b/pkg/services/folder/service.go @@ -55,5 +55,5 @@ type NestedFolderService interface { // // The map keys are folder uids and the values are the list of child folders // for that parent. - GetTree(ctx context.Context, cmd *GetTreeQuery) (map[string][]*Folder, error) + GetTree(ctx context.Context, cmd *GetTreeQuery) ([]*Folder, error) }