From 2532047e7a6f2bd4ac9b7d7ae3d1b2aadcfb3bd6 Mon Sep 17 00:00:00 2001 From: idafurjes <36131195+idafurjes@users.noreply.github.com> Date: Fri, 1 Mar 2024 10:16:33 +0100 Subject: [PATCH] Add FolderUID for library elements (#79572) * Add FolderUID in missing places for libraryelements * Add migration for FolderUID in library elements table * Add Folder UIDs tolibrary panels * Adjust dashboard import with folder uid * Fix lint * Rename back FolderUID to UID * Remove default * Check if folderUID is nil * Add unique indes on org_id,folder_uid,name and kind * Update pkg/services/libraryelements/database.go Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * Fix folder integration test, with unique index on library elements * Make folder uids nullable and rewrite migration query * Use dashboard uid instead of folder_uid * Adjust test --------- Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> --- pkg/api/dashboard_test.go | 2 +- .../dashboardimport/service/service.go | 2 +- .../dashboardimport/service/service_test.go | 19 +++--- pkg/services/folder/folderimpl/folder_test.go | 6 ++ pkg/services/libraryelements/database.go | 20 ++++-- .../libraryelements_create_test.go | 15 ++-- .../libraryelements_delete_test.go | 2 +- .../libraryelements_get_all_test.go | 67 +++++++++++------- .../libraryelements_get_test.go | 4 +- .../libraryelements_patch_test.go | 68 +++++++++++-------- .../libraryelements_permissions_test.go | 37 +++++----- .../libraryelements/libraryelements_test.go | 30 ++++---- pkg/services/libraryelements/model/model.go | 18 ++--- pkg/services/libraryelements/writers.go | 2 + pkg/services/librarypanels/librarypanels.go | 21 +++--- .../librarypanels/librarypanels_test.go | 51 +++++++------- .../sqlstore/migrations/libraryelements.go | 22 ++++++ 17 files changed, 229 insertions(+), 157 deletions(-) diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index bede8c3cfd6..733217495a4 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -1037,7 +1037,7 @@ func (m *mockLibraryPanelService) ConnectLibraryPanelsForDashboard(c context.Con return nil } -func (m *mockLibraryPanelService) ImportLibraryPanelsForDashboard(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error { +func (m *mockLibraryPanelService) ImportLibraryPanelsForDashboard(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64, folderUID string) error { return nil } diff --git a/pkg/services/dashboardimport/service/service.go b/pkg/services/dashboardimport/service/service.go index 842651e2759..00cd032496c 100644 --- a/pkg/services/dashboardimport/service/service.go +++ b/pkg/services/dashboardimport/service/service.go @@ -141,7 +141,7 @@ func (s *ImportDashboardService) ImportDashboard(ctx context.Context, req *dashb metrics.MFolderIDsServiceCount.WithLabelValues(metrics.DashboardImport).Inc() // nolint:staticcheck - err = s.libraryPanelService.ImportLibraryPanelsForDashboard(ctx, req.User, libraryElements, generatedDash.Get("panels").MustArray(), req.FolderId) + err = s.libraryPanelService.ImportLibraryPanelsForDashboard(ctx, req.User, libraryElements, generatedDash.Get("panels").MustArray(), req.FolderId, req.FolderUid) if err != nil { return nil, err } diff --git a/pkg/services/dashboardimport/service/service_test.go b/pkg/services/dashboardimport/service/service_test.go index 19e0dba8937..e8958f22c9c 100644 --- a/pkg/services/dashboardimport/service/service_test.go +++ b/pkg/services/dashboardimport/service/service_test.go @@ -47,7 +47,7 @@ func TestImportDashboardService(t *testing.T) { importLibraryPanelsForDashboard := false connectLibraryPanelsForDashboardCalled := false libraryPanelService := &libraryPanelServiceMock{ - importLibraryPanelsForDashboardFunc: func(ctx context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error { + importLibraryPanelsForDashboardFunc: func(ctx context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64, folderUID string) error { importLibraryPanelsForDashboard = true return nil }, @@ -75,9 +75,8 @@ func TestImportDashboardService(t *testing.T) { Inputs: []dashboardimport.ImportDashboardInput{ {Name: "*", Type: "datasource", Value: "prom"}, }, - User: &user.SignedInUser{UserID: 2, OrgRole: org.RoleAdmin, OrgID: 3}, - // FolderId: 5, - FolderUid: "123", + User: &user.SignedInUser{UserID: 2, OrgRole: org.RoleAdmin, OrgID: 3}, + FolderUid: "folderUID", } resp, err := s.ImportDashboard(context.Background(), req) require.NoError(t, err) @@ -91,7 +90,7 @@ func TestImportDashboardService(t *testing.T) { require.Equal(t, int64(3), importDashboardArg.OrgID) require.Equal(t, int64(2), userID) require.Equal(t, "prometheus", importDashboardArg.Dashboard.PluginID) - require.Equal(t, "123", importDashboardArg.Dashboard.FolderUID) + require.Equal(t, "folderUID", importDashboardArg.Dashboard.FolderUID) panel := importDashboardArg.Dashboard.Data.Get("panels").GetIndex(0) require.Equal(t, "prom", panel.Get("datasource").MustString()) @@ -143,7 +142,7 @@ func TestImportDashboardService(t *testing.T) { {Name: "*", Type: "datasource", Value: "prom"}, }, User: &user.SignedInUser{UserID: 2, OrgRole: org.RoleAdmin, OrgID: 3}, - FolderUid: "123", + FolderUid: "folderUID", } resp, err := s.ImportDashboard(context.Background(), req) require.NoError(t, err) @@ -157,7 +156,7 @@ func TestImportDashboardService(t *testing.T) { require.Equal(t, int64(3), importDashboardArg.OrgID) require.Equal(t, int64(2), userID) require.Equal(t, "", importDashboardArg.Dashboard.PluginID) - require.Equal(t, "123", importDashboardArg.Dashboard.FolderUID) + require.Equal(t, "folderUID", importDashboardArg.Dashboard.FolderUID) panel := importDashboardArg.Dashboard.Data.Get("panels").GetIndex(0) require.Equal(t, "prom", panel.Get("datasource").MustString()) @@ -211,7 +210,7 @@ func (s *dashboardServiceMock) ImportDashboard(ctx context.Context, dto *dashboa type libraryPanelServiceMock struct { librarypanels.Service connectLibraryPanelsForDashboardFunc func(c context.Context, signedInUser identity.Requester, dash *dashboards.Dashboard) error - importLibraryPanelsForDashboardFunc func(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error + importLibraryPanelsForDashboardFunc func(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64, folderUID string) error } var _ librarypanels.Service = (*libraryPanelServiceMock)(nil) @@ -224,9 +223,9 @@ func (s *libraryPanelServiceMock) ConnectLibraryPanelsForDashboard(ctx context.C return nil } -func (s *libraryPanelServiceMock) ImportLibraryPanelsForDashboard(ctx context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error { +func (s *libraryPanelServiceMock) ImportLibraryPanelsForDashboard(ctx context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64, folderUID string) error { if s.importLibraryPanelsForDashboardFunc != nil { - return s.importLibraryPanelsForDashboardFunc(ctx, signedInUser, libraryPanels, panels, folderID) + return s.importLibraryPanelsForDashboardFunc(ctx, signedInUser, libraryPanels, panels, folderID, folderUID) } return nil diff --git a/pkg/services/folder/folderimpl/folder_test.go b/pkg/services/folder/folderimpl/folder_test.go index e23fe64f206..17b10376f6d 100644 --- a/pkg/services/folder/folderimpl/folder_test.go +++ b/pkg/services/folder/folderimpl/folder_test.go @@ -448,10 +448,12 @@ func TestIntegrationNestedFolderService(t *testing.T) { // nolint:staticcheck libraryElementCmd.FolderID = parent.ID + libraryElementCmd.FolderUID = &parent.UID _, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) require.NoError(t, err) // nolint:staticcheck libraryElementCmd.FolderID = subfolder.ID + libraryElementCmd.FolderUID = &subfolder.UID _, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) require.NoError(t, err) @@ -528,10 +530,12 @@ func TestIntegrationNestedFolderService(t *testing.T) { // nolint:staticcheck libraryElementCmd.FolderID = parent.ID + libraryElementCmd.FolderUID = &parent.UID _, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) require.NoError(t, err) // nolint:staticcheck libraryElementCmd.FolderID = subfolder.ID + libraryElementCmd.FolderUID = &subfolder.UID _, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) require.NoError(t, err) @@ -667,11 +671,13 @@ func TestIntegrationNestedFolderService(t *testing.T) { _ = createRule(t, alertStore, subfolder.UID, "sub alert") // nolint:staticcheck libraryElementCmd.FolderID = subfolder.ID + libraryElementCmd.FolderUID = &subPanel.FolderUID subPanel, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) require.NoError(t, err) } // nolint:staticcheck libraryElementCmd.FolderID = parent.ID + libraryElementCmd.FolderUID = &parent.UID parentPanel, err := lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) require.NoError(t, err) diff --git a/pkg/services/libraryelements/database.go b/pkg/services/libraryelements/database.go index b8c09c12816..2aba478bd47 100644 --- a/pkg/services/libraryelements/database.go +++ b/pkg/services/libraryelements/database.go @@ -149,14 +149,20 @@ func (l *LibraryElementService) createLibraryElement(c context.Context, signedIn } metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryElements).Inc() + // folderUID *string will be changed to string + var folderUID string + if cmd.FolderUID != nil { + folderUID = *cmd.FolderUID + } element := model.LibraryElement{ - OrgID: signedInUser.GetOrgID(), - FolderID: cmd.FolderID, // nolint:staticcheck - UID: createUID, - Name: cmd.Name, - Model: updatedModel, - Version: 1, - Kind: cmd.Kind, + OrgID: signedInUser.GetOrgID(), + FolderID: cmd.FolderID, // nolint:staticcheck + FolderUID: folderUID, + UID: createUID, + Name: cmd.Name, + Model: updatedModel, + Version: 1, + Kind: cmd.Kind, Created: time.Now(), Updated: time.Now(), diff --git a/pkg/services/libraryelements/libraryelements_create_test.go b/pkg/services/libraryelements/libraryelements_create_test.go index 8a1dfac99bc..7adca02ebd1 100644 --- a/pkg/services/libraryelements/libraryelements_create_test.go +++ b/pkg/services/libraryelements/libraryelements_create_test.go @@ -15,7 +15,7 @@ func TestCreateLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to create a library panel that already exists, it should fail", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 400, resp.Status()) @@ -28,6 +28,7 @@ func TestCreateLibraryElement(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: sc.initialResult.Result.UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -68,7 +69,7 @@ func TestCreateLibraryElement(t *testing.T) { testScenario(t, "When an admin tries to create a library panel that does not exists using an nonexistent UID, it should succeed", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Nonexistent UID") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Nonexistent UID") command.UID = util.GenerateShortUID() sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) @@ -78,6 +79,7 @@ func TestCreateLibraryElement(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: command.UID, Name: "Nonexistent UID", Kind: int64(model.PanelElement), @@ -118,7 +120,7 @@ func TestCreateLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to create a library panel that does not exists using an existent UID, it should fail", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Existing UID") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Existing UID") command.UID = sc.initialResult.Result.UID sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) @@ -128,7 +130,7 @@ func TestCreateLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to create a library panel that does not exists using an invalid UID, it should fail", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Invalid UID") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Invalid UID") command.UID = "Testing an invalid UID" sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) @@ -138,7 +140,7 @@ func TestCreateLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to create a library panel that does not exists using an UID that is too long, it should fail", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Invalid UID") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Invalid UID") command.UID = "j6T00KRZzj6T00KRZzj6T00KRZzj6T00KRZzj6T00K" sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) @@ -147,7 +149,7 @@ func TestCreateLibraryElement(t *testing.T) { testScenario(t, "When an admin tries to create a library panel where name and panel title differ, it should not update panel title", func(t *testing.T, sc scenarioContext) { - command := getCreatePanelCommand(1, "Library Panel Name") + command := getCreatePanelCommand(1, sc.folder.UID, "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) var result = validateAndUnMarshalResponse(t, resp) @@ -156,6 +158,7 @@ func TestCreateLibraryElement(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.UID, Name: "Library Panel Name", Kind: int64(model.PanelElement), diff --git a/pkg/services/libraryelements/libraryelements_delete_test.go b/pkg/services/libraryelements/libraryelements_delete_test.go index 7493c49461c..597787d6ee0 100644 --- a/pkg/services/libraryelements/libraryelements_delete_test.go +++ b/pkg/services/libraryelements/libraryelements_delete_test.go @@ -74,7 +74,7 @@ func TestDeleteLibraryElement(t *testing.T) { Data: simplejson.NewFromAny(dashJSON), } // nolint:staticcheck - dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID) + dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID, sc.folder.UID) err := sc.service.ConnectElementsToDashboard(sc.reqContext.Req.Context(), sc.reqContext.SignedInUser, []string{sc.initialResult.Result.UID}, dashInDB.ID) require.NoError(t, err) diff --git a/pkg/services/libraryelements/libraryelements_get_all_test.go b/pkg/services/libraryelements/libraryelements_get_all_test.go index d281155a1ba..29cc7819fca 100644 --- a/pkg/services/libraryelements/libraryelements_get_all_test.go +++ b/pkg/services/libraryelements/libraryelements_get_all_test.go @@ -39,7 +39,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all panel elements and both panels and variables exist, it should only return panels", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreateVariableCommand(sc.folder.ID, "query0") + command := getCreateVariableCommand(sc.folder.ID, sc.folder.UID, "query0") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -64,6 +64,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -106,7 +107,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all variable elements and both panels and variables exist, it should only return panels", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreateVariableCommand(sc.folder.ID, "query0") + command := getCreateVariableCommand(sc.folder.ID, sc.folder.UID, "query0") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -131,6 +132,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "query0", Kind: int64(model.VariableElement), @@ -172,7 +174,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist, it should succeed", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -193,6 +195,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -228,6 +231,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[1].UID, Name: "Text - Library Panel2", Kind: int64(model.PanelElement), @@ -270,7 +274,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and sort desc is set, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -294,6 +298,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel2", Kind: int64(model.PanelElement), @@ -329,6 +334,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[1].UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -371,7 +377,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and typeFilter is set to existing types, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreateCommandWithModel(sc.folder.ID, "Gauge - Library Panel", model.PanelElement, []byte(` + command := getCreateCommandWithModel(sc.folder.ID, sc.folder.UID, "Gauge - Library Panel", model.PanelElement, []byte(` { "datasource": "${DS_GDEV-TESTDATA}", "id": 1, @@ -385,7 +391,7 @@ func TestGetAllLibraryElements(t *testing.T) { require.Equal(t, 200, resp.Status()) // nolint:staticcheck - command = getCreateCommandWithModel(sc.folder.ID, "BarGauge - Library Panel", model.PanelElement, []byte(` + command = getCreateCommandWithModel(sc.folder.ID, sc.folder.UID, "BarGauge - Library Panel", model.PanelElement, []byte(` { "datasource": "${DS_GDEV-TESTDATA}", "id": 1, @@ -417,6 +423,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 3, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "BarGauge - Library Panel", Kind: int64(model.PanelElement), @@ -452,6 +459,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[1].UID, Name: "Gauge - Library Panel", Kind: int64(model.PanelElement), @@ -494,7 +502,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and typeFilter is set to a nonexistent type, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreateCommandWithModel(sc.folder.ID, "Gauge - Library Panel", model.PanelElement, []byte(` + command := getCreateCommandWithModel(sc.folder.ID, sc.folder.UID, "Gauge - Library Panel", model.PanelElement, []byte(` { "datasource": "${DS_GDEV-TESTDATA}", "id": 1, @@ -529,25 +537,24 @@ func TestGetAllLibraryElements(t *testing.T) { } }) - scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and folderFilter is set to existing folders, it should succeed and the result should be correct", + scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and folderFilterUIDs is set to existing folders, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { newFolder := createFolder(t, sc, "NewFolder") // nolint:staticcheck - command := getCreatePanelCommand(newFolder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(newFolder.ID, newFolder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) - // nolint:staticcheck - folderFilter := strconv.FormatInt(newFolder.ID, 10) - + folderFilterUID := newFolder.UID err := sc.reqContext.Req.ParseForm() require.NoError(t, err) - sc.reqContext.Req.Form.Add("folderFilter", folderFilter) + sc.reqContext.Req.Form.Add("folderFilterUIDs", folderFilterUID) resp = sc.service.getAllHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) var result libraryElementsSearch err = json.Unmarshal(resp.Body(), &result) + require.NoError(t, err) var expected = libraryElementsSearch{ Result: libraryElementsSearchResult{ @@ -559,6 +566,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: newFolder.ID, // nolint:staticcheck + FolderUID: newFolder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel2", Kind: int64(model.PanelElement), @@ -602,15 +610,15 @@ func TestGetAllLibraryElements(t *testing.T) { func(t *testing.T, sc scenarioContext) { newFolder := createFolder(t, sc, "NewFolder") // nolint:staticcheck - command := getCreatePanelCommand(newFolder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(newFolder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) - folderFilter := "2020,2021" + folderFilterUIDs := "2020,2021" err := sc.reqContext.Req.ParseForm() require.NoError(t, err) - sc.reqContext.Req.Form.Add("folderFilter", folderFilter) + sc.reqContext.Req.Form.Add("folderFilterUIDs", folderFilterUIDs) resp = sc.service.getAllHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -633,7 +641,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and folderFilter is set to General folder, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -658,6 +666,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -693,6 +702,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[1].UID, Name: "Text - Library Panel2", Kind: int64(model.PanelElement), @@ -735,7 +745,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and excludeUID is set, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -759,6 +769,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel2", Kind: int64(model.PanelElement), @@ -801,7 +812,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -825,6 +836,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -867,7 +879,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 2, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -892,6 +904,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel2", Kind: int64(model.PanelElement), @@ -934,7 +947,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and searchString exists in the description, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreateCommandWithModel(sc.folder.ID, "Text - Library Panel2", model.PanelElement, []byte(` + command := getCreateCommandWithModel(sc.folder.ID, sc.folder.UID, "Text - Library Panel2", model.PanelElement, []byte(` { "datasource": "${DS_GDEV-TESTDATA}", "id": 1, @@ -968,6 +981,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -1010,7 +1024,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and searchString exists in both name and description, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreateCommandWithModel(sc.folder.ID, "Some Other", model.PanelElement, []byte(` + command := getCreateCommandWithModel(sc.folder.ID, sc.folder.UID, "Some Other", model.PanelElement, []byte(` { "datasource": "${DS_GDEV-TESTDATA}", "id": 1, @@ -1042,6 +1056,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Some Other", Kind: int64(model.PanelElement), @@ -1077,6 +1092,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[1].UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -1119,7 +1135,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 1 and searchString is panel2, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -1145,6 +1161,7 @@ func TestGetAllLibraryElements(t *testing.T) { ID: 2, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: result.Result.Elements[0].UID, Name: "Text - Library Panel2", Kind: int64(model.PanelElement), @@ -1187,7 +1204,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 3 and searchString is panel, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -1219,7 +1236,7 @@ func TestGetAllLibraryElements(t *testing.T) { scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and perPage is 1 and page is 3 and searchString does not exist, it should succeed and the result should be correct", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel2") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel2") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) diff --git a/pkg/services/libraryelements/libraryelements_get_test.go b/pkg/services/libraryelements/libraryelements_get_test.go index 0c8e4893c2d..b441505639b 100644 --- a/pkg/services/libraryelements/libraryelements_get_test.go +++ b/pkg/services/libraryelements/libraryelements_get_test.go @@ -35,6 +35,7 @@ func TestGetLibraryElement(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: res.Result.UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), @@ -123,7 +124,7 @@ func TestGetLibraryElement(t *testing.T) { Data: simplejson.NewFromAny(dashJSON), } // nolint:staticcheck - dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID) + dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID, sc.folder.UID) err := sc.service.ConnectElementsToDashboard(sc.reqContext.Req.Context(), sc.reqContext.SignedInUser, []string{sc.initialResult.Result.UID}, dashInDB.ID) require.NoError(t, err) @@ -133,6 +134,7 @@ func TestGetLibraryElement(t *testing.T) { ID: 1, OrgID: 1, FolderID: 1, // nolint:staticcheck + FolderUID: sc.folder.UID, UID: res.Result.UID, Name: "Text - Library Panel", Kind: int64(model.PanelElement), diff --git a/pkg/services/libraryelements/libraryelements_patch_test.go b/pkg/services/libraryelements/libraryelements_patch_test.go index 0af1d96e7cb..e59a19e29b6 100644 --- a/pkg/services/libraryelements/libraryelements_patch_test.go +++ b/pkg/services/libraryelements/libraryelements_patch_test.go @@ -26,8 +26,9 @@ func TestPatchLibraryElement(t *testing.T) { func(t *testing.T, sc scenarioContext) { newFolder := createFolder(t, sc, "NewFolder") cmd := model.PatchLibraryElementCommand{ - FolderID: newFolder.ID, // nolint:staticcheck - Name: "Panel - New name", + FolderID: newFolder.ID, // nolint:staticcheck + FolderUID: &newFolder.UID, + Name: "Panel - New name", Model: []byte(` { "datasource": "${DS_GDEV-TESTDATA}", @@ -50,6 +51,7 @@ func TestPatchLibraryElement(t *testing.T) { ID: 1, OrgID: 1, FolderID: newFolder.ID, // nolint:staticcheck + FolderUID: newFolder.UID, UID: sc.initialResult.Result.UID, Name: "Panel - New name", Kind: int64(model.PanelElement), @@ -91,9 +93,10 @@ func TestPatchLibraryElement(t *testing.T) { func(t *testing.T, sc scenarioContext) { newFolder := createFolder(t, sc, "NewFolder") cmd := model.PatchLibraryElementCommand{ - FolderID: newFolder.ID, // nolint:staticcheck - Kind: int64(model.PanelElement), - Version: 1, + FolderID: newFolder.ID, // nolint:staticcheck + FolderUID: &newFolder.UID, + Kind: int64(model.PanelElement), + Version: 1, } sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.reqContext.Req.Body = mockRequestBody(cmd) @@ -102,6 +105,7 @@ func TestPatchLibraryElement(t *testing.T) { var result = validateAndUnMarshalResponse(t, resp) // nolint:staticcheck sc.initialResult.Result.FolderID = newFolder.ID + sc.initialResult.Result.FolderUID = newFolder.UID sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = userInDbAvatar sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated @@ -176,10 +180,11 @@ func TestPatchLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to patch a library panel with an UID that is too long, it should fail", func(t *testing.T, sc scenarioContext) { cmd := model.PatchLibraryElementCommand{ - FolderID: -1, // nolint:staticcheck - UID: "j6T00KRZzj6T00KRZzj6T00KRZzj6T00KRZzj6T00K", - Kind: int64(model.PanelElement), - Version: 1, + FolderID: -1, // nolint:staticcheck + FolderUID: &sc.folder.UID, + UID: "j6T00KRZzj6T00KRZzj6T00KRZzj6T00KRZzj6T00K", + Kind: int64(model.PanelElement), + Version: 1, } sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req.Body = mockRequestBody(cmd) @@ -190,16 +195,17 @@ func TestPatchLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to patch a library panel with an existing UID, it should fail", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Existing UID") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Existing UID") command.UID = util.GenerateShortUID() sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) cmd := model.PatchLibraryElementCommand{ - FolderID: -1, // nolint:staticcheck - UID: command.UID, - Kind: int64(model.PanelElement), - Version: 1, + FolderID: -1, // nolint:staticcheck + FolderUID: &sc.folder.UID, + UID: command.UID, + Kind: int64(model.PanelElement), + Version: 1, } sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req.Body = mockRequestBody(cmd) @@ -312,7 +318,7 @@ func TestPatchLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to patch a library panel with a name that already exists, it should fail", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Another Panel") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Another Panel") sc.ctx.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) var result = validateAndUnMarshalResponse(t, resp) @@ -331,14 +337,15 @@ func TestPatchLibraryElement(t *testing.T) { func(t *testing.T, sc scenarioContext) { newFolder := createFolder(t, sc, "NewFolder") // nolint:staticcheck - command := getCreatePanelCommand(newFolder.ID, "Text - Library Panel") + command := getCreatePanelCommand(newFolder.ID, newFolder.UID, "Text - Library Panel") sc.ctx.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) var result = validateAndUnMarshalResponse(t, resp) cmd := model.PatchLibraryElementCommand{ - FolderID: 1, // nolint:staticcheck - Version: 1, - Kind: int64(model.PanelElement), + FolderID: 1, // nolint:staticcheck + FolderUID: &sc.folder.UID, + Version: 1, + Kind: int64(model.PanelElement), } sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req.Body = mockRequestBody(cmd) @@ -349,23 +356,25 @@ func TestPatchLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to patch a library panel in another org, it should fail", func(t *testing.T, sc scenarioContext) { cmd := model.PatchLibraryElementCommand{ - FolderID: sc.folder.ID, // nolint:staticcheck - Version: 1, - Kind: int64(model.PanelElement), + FolderID: sc.folder.ID, // nolint:staticcheck + FolderUID: &sc.folder.UID, + Version: 1, + Kind: int64(model.PanelElement), } sc.reqContext.OrgID = 2 sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req.Body = mockRequestBody(cmd) resp := sc.service.patchHandler(sc.reqContext) - require.Equal(t, 404, resp.Status()) + require.Equal(t, 400, resp.Status()) }) scenarioWithPanel(t, "When an admin tries to patch a library panel with an old version number, it should fail", func(t *testing.T, sc scenarioContext) { cmd := model.PatchLibraryElementCommand{ - FolderID: sc.folder.ID, // nolint:staticcheck - Version: 1, - Kind: int64(model.PanelElement), + FolderID: sc.folder.ID, // nolint:staticcheck + FolderUID: &sc.folder.UID, + Version: 1, + Kind: int64(model.PanelElement), } sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req.Body = mockRequestBody(cmd) @@ -379,9 +388,10 @@ func TestPatchLibraryElement(t *testing.T) { scenarioWithPanel(t, "When an admin tries to patch a library panel with an other kind, it should succeed but panel should not change", func(t *testing.T, sc scenarioContext) { cmd := model.PatchLibraryElementCommand{ - FolderID: sc.folder.ID, // nolint:staticcheck - Version: 1, - Kind: int64(model.VariableElement), + FolderID: sc.folder.ID, // nolint:staticcheck + FolderUID: &sc.folder.UID, + Version: 1, + Kind: int64(model.VariableElement), } sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req.Body = mockRequestBody(cmd) diff --git a/pkg/services/libraryelements/libraryelements_permissions_test.go b/pkg/services/libraryelements/libraryelements_permissions_test.go index bb48d58f532..327366115ae 100644 --- a/pkg/services/libraryelements/libraryelements_permissions_test.go +++ b/pkg/services/libraryelements/libraryelements_permissions_test.go @@ -30,7 +30,7 @@ func TestLibraryElementPermissionsGeneralFolder(t *testing.T) { func(t *testing.T, sc scenarioContext) { sc.reqContext.SignedInUser.OrgRole = testCase.role - command := getCreatePanelCommand(0, "Library Panel Name") + command := getCreatePanelCommand(0, "", "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, testCase.status, resp.Status()) @@ -40,7 +40,7 @@ func TestLibraryElementPermissionsGeneralFolder(t *testing.T) { func(t *testing.T, sc scenarioContext) { folder := createFolder(t, sc, "Folder") // nolint:staticcheck - command := getCreatePanelCommand(folder.ID, "Library Panel Name") + command := getCreatePanelCommand(folder.ID, folder.UID, "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) @@ -57,7 +57,7 @@ func TestLibraryElementPermissionsGeneralFolder(t *testing.T) { testScenario(t, fmt.Sprintf("When %s tries to patch a library panel by moving it from the General folder, it should return correct status", testCase.role), func(t *testing.T, sc scenarioContext) { folder := createFolder(t, sc, "Folder") - command := getCreatePanelCommand(0, "Library Panel Name") + command := getCreatePanelCommand(0, "", "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) @@ -73,7 +73,7 @@ func TestLibraryElementPermissionsGeneralFolder(t *testing.T) { testScenario(t, fmt.Sprintf("When %s tries to delete a library panel in the General folder, it should return correct status", testCase.role), func(t *testing.T, sc scenarioContext) { - cmd := getCreatePanelCommand(0, "Library Panel Name") + cmd := getCreatePanelCommand(0, "", "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(cmd) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) @@ -86,7 +86,7 @@ func TestLibraryElementPermissionsGeneralFolder(t *testing.T) { testScenario(t, fmt.Sprintf("When %s tries to get a library panel from General folder, it should return correct response", testCase.role), func(t *testing.T, sc scenarioContext) { - cmd := getCreatePanelCommand(0, "Library Panel in General Folder") + cmd := getCreatePanelCommand(0, "", "Library Panel in General Folder") sc.reqContext.Req.Body = mockRequestBody(cmd) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) @@ -96,6 +96,7 @@ func TestLibraryElementPermissionsGeneralFolder(t *testing.T) { result.Result.Meta.UpdatedBy.AvatarUrl = userInDbAvatar result.Result.Meta.FolderName = "General" result.Result.Meta.FolderUID = "" + result.Result.FolderUID = "general" sc.reqContext.SignedInUser.OrgRole = testCase.role sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) @@ -111,7 +112,7 @@ func TestLibraryElementPermissionsGeneralFolder(t *testing.T) { testScenario(t, fmt.Sprintf("When %s tries to get all library panels from General folder, it should return correct response", testCase.role), func(t *testing.T, sc scenarioContext) { - cmd := getCreatePanelCommand(0, "Library Panel in General Folder") + cmd := getCreatePanelCommand(0, "", "Library Panel in General Folder") sc.reqContext.Req.Body = mockRequestBody(cmd) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) @@ -183,7 +184,7 @@ func TestLibraryElementCreatePermissions(t *testing.T) { } // nolint:staticcheck - command := getCreatePanelCommand(folder.ID, "Library Panel Name") + command := getCreatePanelCommand(folder.ID, folder.UID, "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, testCase.status, resp.Status()) @@ -236,7 +237,7 @@ func TestLibraryElementPatchPermissions(t *testing.T) { func(t *testing.T, sc scenarioContext) { fromFolder := createFolder(t, sc, "FromFolder") // nolint:staticcheck - command := getCreatePanelCommand(fromFolder.ID, "Library Panel Name") + command := getCreatePanelCommand(fromFolder.ID, fromFolder.UID, "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) @@ -248,7 +249,7 @@ func TestLibraryElementPatchPermissions(t *testing.T) { } // nolint:staticcheck - cmd := model.PatchLibraryElementCommand{FolderID: toFolder.ID, Version: 1, Kind: int64(model.PanelElement)} + cmd := model.PatchLibraryElementCommand{FolderID: toFolder.ID, FolderUID: &toFolder.UID, Version: 1, Kind: int64(model.PanelElement)} sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.reqContext.Req.Body = mockRequestBody(cmd) resp = sc.service.patchHandler(sc.reqContext) @@ -298,7 +299,7 @@ func TestLibraryElementDeletePermissions(t *testing.T) { func(t *testing.T, sc scenarioContext) { folder := createFolder(t, sc, "Folder") // nolint:staticcheck - command := getCreatePanelCommand(folder.ID, "Library Panel Name") + command := getCreatePanelCommand(folder.ID, folder.UID, "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) @@ -317,27 +318,29 @@ func TestLibraryElementDeletePermissions(t *testing.T) { func TestLibraryElementsWithMissingFolders(t *testing.T) { testScenario(t, "When a user tries to create a library panel in a folder that doesn't exist, it should fail", func(t *testing.T, sc scenarioContext) { - command := getCreatePanelCommand(-100, "Library Panel Name") + command := getCreatePanelCommand(0, "badFolderUID", "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) - require.Equal(t, 404, resp.Status()) + fmt.Println(string(resp.Body())) + require.Equal(t, 400, resp.Status()) }) testScenario(t, "When a user tries to patch a library panel by moving it to a folder that doesn't exist, it should fail", func(t *testing.T, sc scenarioContext) { folder := createFolder(t, sc, "Folder") // nolint:staticcheck - command := getCreatePanelCommand(folder.ID, "Library Panel Name") + command := getCreatePanelCommand(folder.ID, folder.UID, "Library Panel Name") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) + folderUID := "badFolderUID" // nolint:staticcheck - cmd := model.PatchLibraryElementCommand{FolderID: -100, Version: 1, Kind: int64(model.PanelElement)} + cmd := model.PatchLibraryElementCommand{FolderID: -100, FolderUID: &folderUID, Version: 1, Kind: int64(model.PanelElement)} sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.reqContext.Req.Body = mockRequestBody(cmd) resp = sc.service.patchHandler(sc.reqContext) - require.Equal(t, 404, resp.Status()) + require.Equal(t, 400, resp.Status()) }) } @@ -367,7 +370,7 @@ func TestLibraryElementsGetPermissions(t *testing.T) { func(t *testing.T, sc scenarioContext) { folder := createFolder(t, sc, "Folder") // nolint:staticcheck - cmd := getCreatePanelCommand(folder.ID, "Library Panel") + cmd := getCreatePanelCommand(folder.ID, folder.UID, "Library Panel") sc.reqContext.Req.Body = mockRequestBody(cmd) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) @@ -418,7 +421,7 @@ func TestLibraryElementsGetAllPermissions(t *testing.T) { for i := 1; i <= 2; i++ { folder := createFolder(t, sc, fmt.Sprintf("Folder%d", i)) // nolint:staticcheck - cmd := getCreatePanelCommand(folder.ID, fmt.Sprintf("Library Panel %d", i)) + cmd := getCreatePanelCommand(folder.ID, folder.UID, fmt.Sprintf("Library Panel %d", i)) sc.reqContext.Req.Body = mockRequestBody(cmd) resp := sc.service.createHandler(sc.reqContext) result := validateAndUnMarshalResponse(t, resp) diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index 1bb0b8abbc0..61a8fecf7c3 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -89,7 +89,7 @@ func TestDeleteLibraryPanelsInFolder(t *testing.T) { Data: simplejson.NewFromAny(dashJSON), } // nolint:staticcheck - dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID) + dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID, sc.folder.UID) err := sc.service.ConnectElementsToDashboard(sc.reqContext.Req.Context(), sc.reqContext.SignedInUser, []string{sc.initialResult.Result.UID}, dashInDB.ID) require.NoError(t, err) @@ -106,7 +106,7 @@ func TestDeleteLibraryPanelsInFolder(t *testing.T) { scenarioWithPanel(t, "When an admin tries to delete a folder that contains disconnected elements, it should delete all disconnected elements too", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreateVariableCommand(sc.folder.ID, "query0") + command := getCreateVariableCommand(sc.folder.ID, sc.folder.UID, "query0") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) require.Equal(t, 200, resp.Status()) @@ -164,7 +164,7 @@ func TestGetLibraryPanelConnections(t *testing.T) { Data: simplejson.NewFromAny(dashJSON), } // nolint:staticcheck - dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID) + dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID, sc.folder.UID) err := sc.service.ConnectElementsToDashboard(sc.reqContext.Req.Context(), sc.reqContext.SignedInUser, []string{sc.initialResult.Result.UID}, dashInDB.ID) require.NoError(t, err) @@ -203,6 +203,7 @@ type libraryElement struct { OrgID int64 `json:"orgId"` // Deprecated: use FolderUID instead FolderID int64 `json:"folderId"` + FolderUID string `json:"folderUid"` UID string `json:"uid"` Name string `json:"name"` Kind int64 `json:"kind"` @@ -232,8 +233,8 @@ type libraryElementsSearchResult struct { PerPage int `json:"perPage"` } -func getCreatePanelCommand(folderID int64, name string) model.CreateLibraryElementCommand { - command := getCreateCommandWithModel(folderID, name, model.PanelElement, []byte(` +func getCreatePanelCommand(folderID int64, folderUID string, name string) model.CreateLibraryElementCommand { + command := getCreateCommandWithModel(folderID, folderUID, name, model.PanelElement, []byte(` { "datasource": "${DS_GDEV-TESTDATA}", "id": 1, @@ -246,8 +247,8 @@ func getCreatePanelCommand(folderID int64, name string) model.CreateLibraryEleme return command } -func getCreateVariableCommand(folderID int64, name string) model.CreateLibraryElementCommand { - command := getCreateCommandWithModel(folderID, name, model.VariableElement, []byte(` +func getCreateVariableCommand(folderID int64, folderUID, name string) model.CreateLibraryElementCommand { + command := getCreateCommandWithModel(folderID, folderUID, name, model.VariableElement, []byte(` { "datasource": "${DS_GDEV-TESTDATA}", "name": "query0", @@ -259,12 +260,12 @@ func getCreateVariableCommand(folderID int64, name string) model.CreateLibraryEl return command } -func getCreateCommandWithModel(folderID int64, name string, kind model.LibraryElementKind, byteModel []byte) model.CreateLibraryElementCommand { +func getCreateCommandWithModel(folderID int64, folderUID, name string, kind model.LibraryElementKind, byteModel []byte) model.CreateLibraryElementCommand { command := model.CreateLibraryElementCommand{ - FolderID: folderID, // nolint:staticcheck - Name: name, - Model: byteModel, - Kind: int64(kind), + FolderUID: &folderUID, + Name: name, + Model: byteModel, + Kind: int64(kind), } return command @@ -281,9 +282,10 @@ type scenarioContext struct { log log.Logger } -func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash *dashboards.Dashboard, folderID int64) *dashboards.Dashboard { +func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash *dashboards.Dashboard, folderID int64, folderUID string) *dashboards.Dashboard { // nolint:staticcheck dash.FolderID = folderID + dash.FolderUID = folderUID dashItem := &dashboards.SaveDashboardDTO{ Dashboard: dash, Message: "", @@ -398,7 +400,7 @@ func scenarioWithPanel(t *testing.T, desc string, fn func(t *testing.T, sc scena testScenario(t, desc, func(t *testing.T, sc scenarioContext) { // nolint:staticcheck - command := getCreatePanelCommand(sc.folder.ID, "Text - Library Panel") + command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) sc.initialResult = validateAndUnMarshalResponse(t, resp) diff --git a/pkg/services/libraryelements/model/model.go b/pkg/services/libraryelements/model/model.go index df8c1abd7a4..e53ef13816f 100644 --- a/pkg/services/libraryelements/model/model.go +++ b/pkg/services/libraryelements/model/model.go @@ -20,6 +20,7 @@ type LibraryElement struct { OrgID int64 `xorm:"org_id"` // Deprecated: use FolderUID instead FolderID int64 `xorm:"folder_id"` + FolderUID string `xorm:"folder_uid"` UID string `xorm:"uid"` Name string Kind int64 @@ -41,6 +42,7 @@ type LibraryElementWithMeta struct { OrgID int64 `xorm:"org_id"` // Deprecated: use FolderUID instead FolderID int64 `xorm:"folder_id"` + FolderUID string `xorm:"folder_uid"` UID string `xorm:"uid"` Name string Kind int64 @@ -53,7 +55,6 @@ type LibraryElementWithMeta struct { Updated time.Time FolderName string - FolderUID string `xorm:"folder_uid"` ConnectedDashboards int64 CreatedBy int64 UpdatedBy int64 @@ -217,13 +218,14 @@ type GetLibraryElementCommand struct { // SearchLibraryElementsQuery is the query used for searching for Elements type SearchLibraryElementsQuery struct { - PerPage int - Page int - SearchString string - SortDirection string - Kind int - TypeFilter string - ExcludeUID string + PerPage int + Page int + SearchString string + SortDirection string + Kind int + TypeFilter string + ExcludeUID string + // Deprecated: use FolderFilterUIDs instead FolderFilter string FolderFilterUIDs string } diff --git a/pkg/services/libraryelements/writers.go b/pkg/services/libraryelements/writers.go index e1d470f6cdc..18781637fac 100644 --- a/pkg/services/libraryelements/writers.go +++ b/pkg/services/libraryelements/writers.go @@ -82,6 +82,7 @@ type FolderFilter struct { func parseFolderFilter(query model.SearchLibraryElementsQuery) FolderFilter { folderIDs := make([]string, 0) folderUIDs := make([]string, 0) + // nolint:staticcheck hasFolderFilter := len(strings.TrimSpace(query.FolderFilter)) > 0 hasFolderFilterUID := len(strings.TrimSpace(query.FolderFilterUIDs)) > 0 @@ -100,6 +101,7 @@ func parseFolderFilter(query model.SearchLibraryElementsQuery) FolderFilter { if hasFolderFilter { result.includeGeneralFolder = false + // nolint:staticcheck folderIDs = strings.Split(query.FolderFilter, ",") metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryElements).Inc() // nolint:staticcheck diff --git a/pkg/services/librarypanels/librarypanels.go b/pkg/services/librarypanels/librarypanels.go index 244f925ddeb..91fd6107a5d 100644 --- a/pkg/services/librarypanels/librarypanels.go +++ b/pkg/services/librarypanels/librarypanels.go @@ -42,7 +42,7 @@ func ProvideService(cfg *setting.Cfg, sqlStore db.DB, routeRegister routing.Rout // Service is a service for operating on library panels. type Service interface { ConnectLibraryPanelsForDashboard(c context.Context, signedInUser identity.Requester, dash *dashboards.Dashboard) error - ImportLibraryPanelsForDashboard(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error + ImportLibraryPanelsForDashboard(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64, folderUID string) error } type LibraryInfo struct { @@ -117,11 +117,11 @@ func connectLibraryPanelsRecursively(c context.Context, panels []any, libraryPan } // ImportLibraryPanelsForDashboard loops through all panels in dashboard JSON and creates any missing library panels in the database. -func (lps *LibraryPanelService) ImportLibraryPanelsForDashboard(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error { - return importLibraryPanelsRecursively(c, lps.LibraryElementService, signedInUser, libraryPanels, panels, folderID) +func (lps *LibraryPanelService) ImportLibraryPanelsForDashboard(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64, folderUID string) error { + return importLibraryPanelsRecursively(c, lps.LibraryElementService, signedInUser, libraryPanels, panels, folderID, folderUID) } -func importLibraryPanelsRecursively(c context.Context, service libraryelements.Service, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error { +func importLibraryPanelsRecursively(c context.Context, service libraryelements.Service, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64, folderUID string) error { for _, panel := range panels { panelAsJSON := simplejson.NewFromAny(panel) libraryPanel := panelAsJSON.Get("libraryPanel") @@ -132,7 +132,7 @@ func importLibraryPanelsRecursively(c context.Context, service libraryelements.S // we have a row if panelType == "row" { - err := importLibraryPanelsRecursively(c, service, signedInUser, libraryPanels, panelAsJSON.Get("panels").MustArray(), folderID) + err := importLibraryPanelsRecursively(c, service, signedInUser, libraryPanels, panelAsJSON.Get("panels").MustArray(), folderID, folderUID) if err != nil { return err } @@ -168,11 +168,12 @@ func importLibraryPanelsRecursively(c context.Context, service libraryelements.S metrics.MFolderIDsServiceCount.WithLabelValues(metrics.LibraryPanels).Inc() var cmd = model.CreateLibraryElementCommand{ - FolderID: folderID, // nolint:staticcheck - Name: name, - Model: Model, - Kind: int64(model.PanelElement), - UID: UID, + FolderID: folderID, // nolint:staticcheck + FolderUID: &folderUID, + Name: name, + Model: Model, + Kind: int64(model.PanelElement), + UID: UID, } _, err = service.CreateElement(c, signedInUser, cmd) if err != nil { diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index dae0821acf7..577ee20aebd 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -86,8 +86,7 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) { Title: "Testing ConnectLibraryPanelsForDashboard", Data: simplejson.NewFromAny(dashJSON), } - // nolint:staticcheck - dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID) + dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash) err := sc.service.ConnectLibraryPanelsForDashboard(sc.ctx, sc.user, dashInDB) require.NoError(t, err) @@ -101,8 +100,7 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) { scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with library panels inside and outside of rows, it should connect all", func(t *testing.T, sc scenarioContext) { cmd := model.CreateLibraryElementCommand{ - FolderID: sc.initialResult.Result.FolderID, // nolint:staticcheck - Name: "Outside row", + Name: "Outside row", Model: []byte(` { "datasource": "${DS_GDEV-TESTDATA}", @@ -112,7 +110,8 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) { "description": "A description" } `), - Kind: int64(model.PanelElement), + Kind: int64(model.PanelElement), + FolderUID: &sc.folder.UID, } outsidePanel, err := sc.elementService.CreateElement(sc.ctx, sc.user, cmd) require.NoError(t, err) @@ -185,8 +184,7 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) { Title: "Testing ConnectLibraryPanelsForDashboard", Data: simplejson.NewFromAny(dashJSON), } - // nolint:staticcheck - dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID) + dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash) err = sc.service.ConnectLibraryPanelsForDashboard(sc.ctx, sc.user, dashInDB) require.NoError(t, err) @@ -232,8 +230,7 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) { Title: "Testing ConnectLibraryPanelsForDashboard", Data: simplejson.NewFromAny(dashJSON), } - // nolint:staticcheck - dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID) + dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash) err := sc.service.ConnectLibraryPanelsForDashboard(sc.ctx, sc.user, dashInDB) require.EqualError(t, err, errLibraryPanelHeaderUIDMissing.Error()) @@ -242,8 +239,7 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) { scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with unused/removed library panels, it should disconnect unused/removed library panels", func(t *testing.T, sc scenarioContext) { unused, err := sc.elementService.CreateElement(sc.ctx, sc.user, model.CreateLibraryElementCommand{ - FolderID: sc.folder.ID, // nolint:staticcheck - Name: "Unused Libray Panel", + Name: "Unused Libray Panel", Model: []byte(` { "datasource": "${DS_GDEV-TESTDATA}", @@ -253,7 +249,8 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) { "description": "Unused description" } `), - Kind: int64(model.PanelElement), + Kind: int64(model.PanelElement), + FolderUID: &sc.folder.UID, }) require.NoError(t, err) dashJSON := map[string]any{ @@ -289,8 +286,7 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) { Title: "Testing ConnectLibraryPanelsForDashboard", Data: simplejson.NewFromAny(dashJSON), } - // nolint:staticcheck - dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.ID) + dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash) err = sc.elementService.ConnectElementsToDashboard(sc.ctx, sc.user, []string{sc.initialResult.Result.UID}, dashInDB.ID) require.NoError(t, err) @@ -399,7 +395,7 @@ func TestImportLibraryPanelsForDashboard(t *testing.T) { require.EqualError(t, err, model.ErrLibraryElementNotFound.Error()) - err = sc.service.ImportLibraryPanelsForDashboard(sc.ctx, sc.user, simplejson.NewFromAny(libraryElements), panels, 0) + err = sc.service.ImportLibraryPanelsForDashboard(sc.ctx, sc.user, simplejson.NewFromAny(libraryElements), panels, 0, "") require.NoError(t, err) element, err := sc.elementService.GetElement(sc.ctx, sc.user, @@ -440,14 +436,14 @@ func TestImportLibraryPanelsForDashboard(t *testing.T) { require.NoError(t, err) // nolint:staticcheck - err = sc.service.ImportLibraryPanelsForDashboard(sc.ctx, sc.user, simplejson.New(), panels, sc.folder.ID) + err = sc.service.ImportLibraryPanelsForDashboard(sc.ctx, sc.user, simplejson.New(), panels, sc.folder.ID, sc.folder.UID) require.NoError(t, err) element, err := sc.elementService.GetElement(sc.ctx, sc.user, model.GetLibraryElementCommand{UID: existingUID, FolderName: dashboards.RootFolderName}) require.NoError(t, err) var expected = getExpected(t, element, existingUID, existingName, sc.initialResult.Result.Model) - expected.FolderID = sc.initialResult.Result.FolderID + expected.FolderUID = sc.initialResult.Result.FolderUID expected.Description = sc.initialResult.Result.Description expected.Meta.FolderUID = sc.folder.UID expected.Meta.FolderName = sc.folder.Title @@ -556,7 +552,7 @@ func TestImportLibraryPanelsForDashboard(t *testing.T) { _, err = sc.elementService.GetElement(sc.ctx, sc.user, model.GetLibraryElementCommand{UID: insideUID, FolderName: dashboards.RootFolderName}) require.EqualError(t, err, model.ErrLibraryElementNotFound.Error()) - err = sc.service.ImportLibraryPanelsForDashboard(sc.ctx, sc.user, simplejson.NewFromAny(libraryElements), panels, 0) + err = sc.service.ImportLibraryPanelsForDashboard(sc.ctx, sc.user, simplejson.NewFromAny(libraryElements), panels, 0, "") require.NoError(t, err) element, err := sc.elementService.GetElement(sc.ctx, sc.user, model.GetLibraryElementCommand{UID: outsideUID, FolderName: dashboards.RootFolderName}) @@ -578,9 +574,11 @@ func TestImportLibraryPanelsForDashboard(t *testing.T) { } type libraryPanel struct { - ID int64 - OrgID int64 + ID int64 + OrgID int64 + // Deprecated: use FolderUID instead FolderID int64 + FolderUID string UID string Name string Type string @@ -616,6 +614,7 @@ type libraryElement struct { ID int64 `json:"id"` OrgID int64 `json:"orgId"` FolderID int64 `json:"folderId"` + FolderUID string `json:"folderUid"` UID string `json:"uid"` Name string `json:"name"` Kind int64 `json:"kind"` @@ -649,7 +648,6 @@ func toLibraryElement(t *testing.T, res model.LibraryElementDTO) libraryElement return libraryElement{ ID: res.ID, OrgID: res.OrgID, - FolderID: res.FolderID, // nolint:staticcheck UID: res.UID, Name: res.Name, Type: res.Type, @@ -715,9 +713,7 @@ func getExpected(t *testing.T, res model.LibraryElementDTO, UID string, name str } } -func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash *dashboards.Dashboard, folderID int64) *dashboards.Dashboard { - // nolint:staticcheck - dash.FolderID = folderID +func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash *dashboards.Dashboard) *dashboards.Dashboard { dashItem := &dashboards.SaveDashboardDTO{ Dashboard: dash, Message: "", @@ -774,8 +770,9 @@ func scenarioWithLibraryPanel(t *testing.T, desc string, fn func(t *testing.T, s testScenario(t, desc, func(t *testing.T, sc scenarioContext) { command := model.CreateLibraryElementCommand{ - FolderID: sc.folder.ID, // nolint:staticcheck - Name: "Text - Library Panel", + FolderID: sc.folder.ID, // nolint:staticcheck + FolderUID: &sc.folder.UID, + Name: "Text - Library Panel", Model: []byte(` { "datasource": "${DS_GDEV-TESTDATA}", @@ -797,7 +794,7 @@ func scenarioWithLibraryPanel(t *testing.T, desc string, fn func(t *testing.T, s Result: libraryPanel{ ID: resp.ID, OrgID: resp.OrgID, - FolderID: resp.FolderID, // nolint:staticcheck + FolderUID: resp.FolderUID, UID: resp.UID, Name: resp.Name, Type: resp.Type, diff --git a/pkg/services/sqlstore/migrations/libraryelements.go b/pkg/services/sqlstore/migrations/libraryelements.go index 3215cb085bb..88a6a3d0238 100644 --- a/pkg/services/sqlstore/migrations/libraryelements.go +++ b/pkg/services/sqlstore/migrations/libraryelements.go @@ -61,4 +61,26 @@ func addLibraryElementsMigrations(mg *migrator.Migrator) { mg.AddMigration("alter library_element model to mediumtext", migrator.NewRawSQLMigration(""). Mysql("ALTER TABLE library_element MODIFY model MEDIUMTEXT NOT NULL;")) + + q := `UPDATE library_element + SET folder_uid = dashboard.uid + FROM dashboard + WHERE library_element.folder_id = dashboard.folder_id AND library_element.org_id = dashboard.org_id` + + if mg.Dialect.DriverName() == migrator.MySQL { + q = `UPDATE library_element + SET folder_uid = ( + SELECT dashboard.uid + FROM dashboard + WHERE library_element.folder_id = dashboard.folder_id AND library_element.org_id = dashboard.org_id + )` + } + + mg.AddMigration("add library_element folder uid", migrator.NewAddColumnMigration(libraryElementsV1, &migrator.Column{ + Name: "folder_uid", Type: migrator.DB_NVarchar, Length: 40, Nullable: true, + })) + + mg.AddMigration("populate library_element folder_uid", migrator.NewRawSQLMigration(q)) + + mg.AddMigration("add index library_element org_id-folder_uid-name-kind", migrator.NewAddIndexMigration(libraryElementsV1, &migrator.Index{Cols: []string{"org_id", "folder_uid", "name", "kind"}, Type: migrator.UniqueIndex})) }