| 
									
										
										
										
											2018-01-29 20:51:01 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 01:11:50 +08:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/mock" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/dtos" | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol" | 
					
						
							| 
									
										
										
										
											2022-11-24 22:38:55 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol/actest" | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" | 
					
						
							| 
									
										
										
										
											2018-03-07 06:59:45 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/dashboards" | 
					
						
							| 
									
										
										
										
											2022-03-03 22:05:47 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							| 
									
										
										
										
											2022-10-11 03:47:53 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/folder" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/folder/foldertest" | 
					
						
							| 
									
										
										
										
											2022-07-16 00:06:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/quota/quotatest" | 
					
						
							| 
									
										
										
										
											2023-01-30 22:17:53 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/search/model" | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/user" | 
					
						
							| 
									
										
										
										
											2019-03-06 15:09:34 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web/webtest" | 
					
						
							| 
									
										
										
										
											2018-02-21 01:11:50 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | func TestFoldersCreateAPIEndpoint(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-10-11 03:47:53 +08:00
										 |  |  | 	folderService := &foldertest.FakeService{} | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	setUpRBACGuardian(t) | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	folderWithoutParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\"}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type testCase struct { | 
					
						
							|  |  |  | 		description            string | 
					
						
							|  |  |  | 		expectedCode           int | 
					
						
							|  |  |  | 		expectedFolder         *folder.Folder | 
					
						
							|  |  |  | 		expectedFolderSvcError error | 
					
						
							|  |  |  | 		permissions            []accesscontrol.Permission | 
					
						
							|  |  |  | 		withNestedFolders      bool | 
					
						
							|  |  |  | 		input                  string | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tcs := []testCase{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:    "folder creation succeeds given the correct request for creating a folder", | 
					
						
							|  |  |  | 			input:          folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:   http.StatusOK, | 
					
						
							|  |  |  | 			expectedFolder: &folder.Folder{ID: 1, UID: "uid", Title: "Folder"}, | 
					
						
							|  |  |  | 			permissions:    []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:  "folder creation fails without permissions to create a folder", | 
					
						
							|  |  |  | 			input:        folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode: http.StatusForbidden, | 
					
						
							|  |  |  | 			permissions:  []accesscontrol.Permission{}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder creation fails given folder service error %s", | 
					
						
							|  |  |  | 			input:                  folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:           http.StatusConflict, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderWithSameUIDExists, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder creation fails given folder service error %s", | 
					
						
							|  |  |  | 			input:                  folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:           http.StatusBadRequest, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderTitleEmpty, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder creation fails given folder service error %s", | 
					
						
							|  |  |  | 			input:                  folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:           http.StatusBadRequest, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrDashboardInvalidUid, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder creation fails given folder service error %s", | 
					
						
							|  |  |  | 			input:                  folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:           http.StatusBadRequest, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrDashboardUidTooLong, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder creation fails given folder service error %s", | 
					
						
							|  |  |  | 			input:                  folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:           http.StatusConflict, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderSameNameExists, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder creation fails given folder service error %s", | 
					
						
							|  |  |  | 			input:                  folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:           http.StatusForbidden, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderAccessDenied, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder creation fails given folder service error %s", | 
					
						
							|  |  |  | 			input:                  folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:           http.StatusNotFound, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderNotFound, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder creation fails given folder service error %s", | 
					
						
							|  |  |  | 			input:                  folderWithoutParentInput, | 
					
						
							|  |  |  | 			expectedCode:           http.StatusPreconditionFailed, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderVersionMismatch, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersCreate}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tc := range tcs { | 
					
						
							|  |  |  | 		folderService.ExpectedFolder = tc.expectedFolder | 
					
						
							|  |  |  | 		folderService.ExpectedError = tc.expectedFolderSvcError | 
					
						
							|  |  |  | 		folderPermService := acmock.NewMockedPermissionsService() | 
					
						
							|  |  |  | 		folderPermService.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		srv := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							| 
									
										
										
										
											2023-08-25 23:13:46 +08:00
										 |  |  | 			hs.Cfg = setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			if tc.withNestedFolders { | 
					
						
							|  |  |  | 				hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			hs.folderService = folderService | 
					
						
							|  |  |  | 			hs.folderPermissionsService = folderPermService | 
					
						
							|  |  |  | 			hs.accesscontrolService = actest.FakeService{} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Run(testDescription(tc.description, tc.expectedFolderSvcError), func(t *testing.T) { | 
					
						
							|  |  |  | 			input := strings.NewReader(tc.input) | 
					
						
							|  |  |  | 			req := srv.NewPostRequest("/api/folders", input) | 
					
						
							|  |  |  | 			req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions)) | 
					
						
							|  |  |  | 			resp, err := srv.SendJSON(req) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			require.Equal(t, tc.expectedCode, resp.StatusCode) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			folder := dtos.Folder{} | 
					
						
							|  |  |  | 			err = json.NewDecoder(resp.Body).Decode(&folder) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			require.NoError(t, resp.Body.Close()) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			if tc.expectedCode == http.StatusOK { | 
					
						
							| 
									
										
										
										
											2020-11-13 16:52:38 +08:00
										 |  |  | 				assert.Equal(t, int64(1), folder.Id) | 
					
						
							|  |  |  | 				assert.Equal(t, "uid", folder.Uid) | 
					
						
							|  |  |  | 				assert.Equal(t, "Folder", folder.Title) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-10-11 03:47:53 +08:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | func TestFoldersUpdateAPIEndpoint(t *testing.T) { | 
					
						
							|  |  |  | 	folderService := &foldertest.FakeService{} | 
					
						
							|  |  |  | 	setUpRBACGuardian(t) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	type testCase struct { | 
					
						
							|  |  |  | 		description            string | 
					
						
							|  |  |  | 		expectedCode           int | 
					
						
							|  |  |  | 		expectedFolder         *folder.Folder | 
					
						
							|  |  |  | 		expectedFolderSvcError error | 
					
						
							|  |  |  | 		permissions            []accesscontrol.Permission | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tcs := []testCase{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:    "folder updating succeeds given the correct request and permissions to update a folder", | 
					
						
							|  |  |  | 			expectedCode:   http.StatusOK, | 
					
						
							|  |  |  | 			expectedFolder: &folder.Folder{ID: 1, UID: "uid", Title: "Folder upd"}, | 
					
						
							|  |  |  | 			permissions:    []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:  "folder updating fails without permissions to update a folder", | 
					
						
							|  |  |  | 			expectedCode: http.StatusForbidden, | 
					
						
							|  |  |  | 			permissions:  []accesscontrol.Permission{}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder updating fails given folder service error %s", | 
					
						
							|  |  |  | 			expectedCode:           http.StatusConflict, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderWithSameUIDExists, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder updating fails given folder service error %s", | 
					
						
							|  |  |  | 			expectedCode:           http.StatusBadRequest, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderTitleEmpty, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder updating fails given folder service error %s", | 
					
						
							|  |  |  | 			expectedCode:           http.StatusBadRequest, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrDashboardInvalidUid, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder updating fails given folder service error %s", | 
					
						
							|  |  |  | 			expectedCode:           http.StatusBadRequest, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrDashboardUidTooLong, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder updating fails given folder service error %s", | 
					
						
							|  |  |  | 			expectedCode:           http.StatusConflict, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderSameNameExists, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder updating fails given folder service error %s", | 
					
						
							|  |  |  | 			expectedCode:           http.StatusForbidden, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderAccessDenied, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder updating fails given folder service error %s", | 
					
						
							|  |  |  | 			expectedCode:           http.StatusNotFound, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderNotFound, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:            "folder updating fails given folder service error %s", | 
					
						
							|  |  |  | 			expectedCode:           http.StatusPreconditionFailed, | 
					
						
							|  |  |  | 			expectedFolderSvcError: dashboards.ErrFolderVersionMismatch, | 
					
						
							|  |  |  | 			permissions:            []accesscontrol.Permission{{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tc := range tcs { | 
					
						
							|  |  |  | 		folderService.ExpectedFolder = tc.expectedFolder | 
					
						
							|  |  |  | 		folderService.ExpectedError = tc.expectedFolderSvcError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		srv := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							| 
									
										
										
										
											2023-08-25 23:13:46 +08:00
										 |  |  | 			hs.Cfg = setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			hs.folderService = folderService | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		t.Run(testDescription(tc.description, tc.expectedFolderSvcError), func(t *testing.T) { | 
					
						
							|  |  |  | 			input := strings.NewReader("{ \"uid\": \"uid\", \"title\": \"Folder upd\" }") | 
					
						
							|  |  |  | 			req := srv.NewRequest(http.MethodPut, "/api/folders/uid", input) | 
					
						
							|  |  |  | 			req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions)) | 
					
						
							|  |  |  | 			resp, err := srv.SendJSON(req) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			require.Equal(t, tc.expectedCode, resp.StatusCode) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			folder := dtos.Folder{} | 
					
						
							|  |  |  | 			err = json.NewDecoder(resp.Body).Decode(&folder) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			require.NoError(t, resp.Body.Close()) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			if tc.expectedCode == http.StatusOK { | 
					
						
							| 
									
										
										
										
											2020-11-13 16:52:38 +08:00
										 |  |  | 				assert.Equal(t, int64(1), folder.Id) | 
					
						
							|  |  |  | 				assert.Equal(t, "uid", folder.Uid) | 
					
						
							|  |  |  | 				assert.Equal(t, "Folder upd", folder.Title) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | func testDescription(description string, expectedErr error) string { | 
					
						
							|  |  |  | 	if expectedErr != nil { | 
					
						
							|  |  |  | 		return fmt.Sprintf(description, expectedErr.Error()) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return description | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | func TestHTTPServer_FolderMetadata(t *testing.T) { | 
					
						
							|  |  |  | 	setUpRBACGuardian(t) | 
					
						
							| 
									
										
										
										
											2022-10-11 03:47:53 +08:00
										 |  |  | 	folderService := &foldertest.FakeService{} | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 	features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders) | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	server := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							| 
									
										
										
										
											2023-08-25 23:13:46 +08:00
										 |  |  | 		hs.Cfg = setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 		hs.folderService = folderService | 
					
						
							| 
									
										
										
										
											2022-11-15 03:08:10 +08:00
										 |  |  | 		hs.QuotaService = quotatest.New(false, nil) | 
					
						
							| 
									
										
										
										
											2023-01-23 20:09:09 +08:00
										 |  |  | 		hs.SearchService = &mockSearchService{ | 
					
						
							| 
									
										
										
										
											2023-01-30 22:17:53 +08:00
										 |  |  | 			ExpectedResult: model.HitList{}, | 
					
						
							| 
									
										
										
										
											2023-01-23 20:09:09 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 		hs.Features = features | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 	t.Run("Should attach access control metadata to folder response", func(t *testing.T) { | 
					
						
							|  |  |  | 		folderService.ExpectedFolder = &folder.Folder{UID: "folderUid"} | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 		req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true") | 
					
						
							| 
									
										
										
										
											2022-08-11 19:28:55 +08:00
										 |  |  | 		webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{ | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 			1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{ | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll}, | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 				{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")}, | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 			}), | 
					
						
							|  |  |  | 		}}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, res.StatusCode) | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 		defer func() { require.NoError(t, res.Body.Close()) }() | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 		body := dtos.Folder{} | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 		require.NoError(t, json.NewDecoder(res.Body).Decode(&body)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 		assert.True(t, body.AccessControl[dashboards.ActionFoldersRead]) | 
					
						
							|  |  |  | 		assert.True(t, body.AccessControl[dashboards.ActionFoldersWrite]) | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 	t.Run("Should attach access control metadata to folder response with permissions cascading from nested folders", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 		folderService.ExpectedFolder = &folder.Folder{UID: "folderUid"} | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 		folderService.ExpectedFolders = []*folder.Folder{{UID: "parentUid"}} | 
					
						
							|  |  |  | 		features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders) | 
					
						
							|  |  |  | 		defer func() { | 
					
						
							|  |  |  | 			features = featuremgmt.WithFeatures() | 
					
						
							|  |  |  | 			folderService.ExpectedFolders = nil | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true") | 
					
						
							| 
									
										
										
										
											2022-08-11 19:28:55 +08:00
										 |  |  | 		webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{ | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 			1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{ | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll}, | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 				{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("parentUid")}, | 
					
						
							|  |  |  | 				{Action: dashboards.ActionDashboardsCreate, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")}, | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 			}), | 
					
						
							|  |  |  | 		}}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, res.StatusCode) | 
					
						
							|  |  |  | 		defer func() { require.NoError(t, res.Body.Close()) }() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		body := dtos.Folder{} | 
					
						
							|  |  |  | 		require.NoError(t, json.NewDecoder(res.Body).Decode(&body)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert.True(t, body.AccessControl[dashboards.ActionFoldersRead]) | 
					
						
							|  |  |  | 		assert.True(t, body.AccessControl[dashboards.ActionFoldersWrite]) | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 		assert.True(t, body.AccessControl[dashboards.ActionDashboardsCreate]) | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 22:05:11 +08:00
										 |  |  | 	t.Run("Should not attach access control metadata to folder response", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 		folderService.ExpectedFolder = &folder.Folder{UID: "folderUid"} | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		req := server.NewGetRequest("/api/folders/folderUid") | 
					
						
							| 
									
										
										
										
											2022-08-11 19:28:55 +08:00
										 |  |  | 		webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{ | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 			1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{ | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll}, | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")}, | 
					
						
							|  |  |  | 			}), | 
					
						
							|  |  |  | 		}}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, res.StatusCode) | 
					
						
							|  |  |  | 		defer func() { require.NoError(t, res.Body.Close()) }() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		body := dtos.Folder{} | 
					
						
							|  |  |  | 		require.NoError(t, json.NewDecoder(res.Body).Decode(&body)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert.False(t, body.AccessControl[dashboards.ActionFoldersRead]) | 
					
						
							|  |  |  | 		assert.False(t, body.AccessControl[dashboards.ActionFoldersWrite]) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | func TestFolderMoveAPIEndpoint(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-03-30 16:46:11 +08:00
										 |  |  | 	folderService := &foldertest.FakeService{ | 
					
						
							|  |  |  | 		ExpectedFolder: &folder.Folder{}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-06-22 16:29:26 +08:00
										 |  |  | 	setUpRBACGuardian(t) | 
					
						
							| 
									
										
										
										
											2019-03-06 15:09:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	type testCase struct { | 
					
						
							|  |  |  | 		description  string | 
					
						
							|  |  |  | 		expectedCode int | 
					
						
							|  |  |  | 		permissions  []accesscontrol.Permission | 
					
						
							|  |  |  | 		newParentUid string | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tcs := []testCase{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:  "can move folder to another folder with specific permissions", | 
					
						
							|  |  |  | 			newParentUid: "newParentUid", | 
					
						
							|  |  |  | 			expectedCode: http.StatusOK, | 
					
						
							|  |  |  | 			permissions: []accesscontrol.Permission{ | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")}, | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("newParentUid")}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2023-03-30 16:46:11 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			description:  "can move folder to the root folder with specific permissions", | 
					
						
							|  |  |  | 			newParentUid: "", | 
					
						
							|  |  |  | 			expectedCode: http.StatusOK, | 
					
						
							|  |  |  | 			permissions: []accesscontrol.Permission{ | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			description:  "forbidden to move folder to another folder without the write access on the folder being moved", | 
					
						
							|  |  |  | 			newParentUid: "newParentUid", | 
					
						
							|  |  |  | 			expectedCode: http.StatusForbidden, | 
					
						
							|  |  |  | 			permissions: []accesscontrol.Permission{ | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("newParentUid")}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tc := range tcs { | 
					
						
							|  |  |  | 		srv := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							| 
									
										
										
										
											2023-08-25 23:13:46 +08:00
										 |  |  | 			hs.Cfg = setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders) | 
					
						
							|  |  |  | 			hs.folderService = folderService | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		t.Run(tc.description, func(t *testing.T) { | 
					
						
							|  |  |  | 			input := strings.NewReader(fmt.Sprintf("{ \"parentUid\": \"%s\"}", tc.newParentUid)) | 
					
						
							|  |  |  | 			req := srv.NewRequest(http.MethodPost, "/api/folders/uid/move", input) | 
					
						
							|  |  |  | 			req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions)) | 
					
						
							|  |  |  | 			resp, err := srv.SendJSON(req) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			require.Equal(t, tc.expectedCode, resp.StatusCode) | 
					
						
							|  |  |  | 			require.NoError(t, resp.Body.Close()) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-21 18:24:54 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-04-25 16:22:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestFolderGetAPIEndpoint(t *testing.T) { | 
					
						
							|  |  |  | 	folderService := &foldertest.FakeService{ | 
					
						
							|  |  |  | 		ExpectedFolder: &folder.Folder{ | 
					
						
							|  |  |  | 			ID:    1, | 
					
						
							|  |  |  | 			UID:   "uid", | 
					
						
							|  |  |  | 			Title: "uid title", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		ExpectedFolders: []*folder.Folder{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				UID:   "parent", | 
					
						
							|  |  |  | 				Title: "parent title", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				UID:   "subfolder", | 
					
						
							|  |  |  | 				Title: "subfolder title", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	setUpRBACGuardian(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type testCase struct { | 
					
						
							|  |  |  | 		description          string | 
					
						
							|  |  |  | 		URL                  string | 
					
						
							|  |  |  | 		features             *featuremgmt.FeatureManager | 
					
						
							|  |  |  | 		expectedCode         int | 
					
						
							|  |  |  | 		expectedParentUIDs   []string | 
					
						
							|  |  |  | 		expectedParentTitles []string | 
					
						
							|  |  |  | 		permissions          []accesscontrol.Permission | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tcs := []testCase{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:          "get folder by UID should return parent folders if nested folder are enabled", | 
					
						
							|  |  |  | 			URL:                  "/api/folders/uid", | 
					
						
							|  |  |  | 			expectedCode:         http.StatusOK, | 
					
						
							|  |  |  | 			features:             featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders), | 
					
						
							|  |  |  | 			expectedParentUIDs:   []string{"parent", "subfolder"}, | 
					
						
							|  |  |  | 			expectedParentTitles: []string{"parent title", "subfolder title"}, | 
					
						
							|  |  |  | 			permissions: []accesscontrol.Permission{ | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			description:          "get folder by UID should not return parent folders if nested folder are disabled", | 
					
						
							|  |  |  | 			URL:                  "/api/folders/uid", | 
					
						
							|  |  |  | 			expectedCode:         http.StatusOK, | 
					
						
							|  |  |  | 			features:             featuremgmt.WithFeatures(), | 
					
						
							|  |  |  | 			expectedParentUIDs:   []string{}, | 
					
						
							|  |  |  | 			expectedParentTitles: []string{}, | 
					
						
							|  |  |  | 			permissions: []accesscontrol.Permission{ | 
					
						
							|  |  |  | 				{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("uid")}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tc := range tcs { | 
					
						
							|  |  |  | 		srv := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							| 
									
										
										
										
											2023-08-25 23:13:46 +08:00
										 |  |  | 			hs.Cfg = setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2023-04-25 16:22:20 +08:00
										 |  |  | 			hs.Features = tc.features | 
					
						
							|  |  |  | 			hs.folderService = folderService | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Run(tc.description, func(t *testing.T) { | 
					
						
							|  |  |  | 			req := srv.NewGetRequest(tc.URL) | 
					
						
							|  |  |  | 			req = webtest.RequestWithSignedInUser(req, userWithPermissions(1, tc.permissions)) | 
					
						
							|  |  |  | 			resp, err := srv.Send(req) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			require.Equal(t, tc.expectedCode, resp.StatusCode) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			folder := dtos.Folder{} | 
					
						
							|  |  |  | 			err = json.NewDecoder(resp.Body).Decode(&folder) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			require.Equal(t, len(folder.Parents), len(tc.expectedParentUIDs)) | 
					
						
							|  |  |  | 			require.Equal(t, len(folder.Parents), len(tc.expectedParentTitles)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for i := 0; i < len(tc.expectedParentUIDs); i++ { | 
					
						
							|  |  |  | 				assert.Equal(t, tc.expectedParentUIDs[i], folder.Parents[i].Uid) | 
					
						
							|  |  |  | 				assert.Equal(t, tc.expectedParentTitles[i], folder.Parents[i].Title) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			require.NoError(t, resp.Body.Close()) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |