From a0d1a197e3f981668056694380ec343572eff25f Mon Sep 17 00:00:00 2001 From: "Arati R." <33031346+suntala@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:04:02 +0100 Subject: [PATCH] Folders: Use folder UID when deleting library elements in folder (#98967) * Refactor deleteLibraryElementsInFolderUID to use folder UID only * Convert dashboard error to folder one when deleting library elements * Fix incorrectly set folder UID in nested folder test --------- Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> --- pkg/services/folder/folderimpl/folder_test.go | 2 +- pkg/services/libraryelements/database.go | 31 +++++-------------- pkg/services/libraryelements/guard.go | 26 ++++++++++++++++ 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/pkg/services/folder/folderimpl/folder_test.go b/pkg/services/folder/folderimpl/folder_test.go index fa16db4487a..5cae1927586 100644 --- a/pkg/services/folder/folderimpl/folder_test.go +++ b/pkg/services/folder/folderimpl/folder_test.go @@ -734,7 +734,7 @@ func TestIntegrationNestedFolderService(t *testing.T) { _ = createRule(t, alertStore, subfolder.UID, "sub alert") // nolint:staticcheck libraryElementCmd.FolderID = subfolder.ID - libraryElementCmd.FolderUID = &subPanel.FolderUID + libraryElementCmd.FolderUID = &subfolder.UID subPanel, 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 d1f7eba8e3f..c56432f912f 100644 --- a/pkg/services/libraryelements/database.go +++ b/pkg/services/libraryelements/database.go @@ -832,25 +832,10 @@ func (l *LibraryElementService) disconnectElementsFromDashboardID(c context.Cont // deleteLibraryElementsInFolderUID deletes all Library Elements in a folder. func (l *LibraryElementService) deleteLibraryElementsInFolderUID(c context.Context, signedInUser identity.Requester, folderUID string) error { return l.SQLStore.WithTransactionalDbSession(c, func(session *db.Session) error { - var folderUIDs []struct { - ID int64 `xorm:"id"` - } - err := session.SQL("SELECT id from dashboard WHERE uid=? AND org_id=? AND is_folder=?", folderUID, signedInUser.GetOrgID(), l.SQLStore.GetDialect().BooleanStr(true)).Find(&folderUIDs) - if err != nil { - return err - } - - if len(folderUIDs) == 0 { - return dashboards.ErrFolderNotFound - } - - if len(folderUIDs) != 1 { - return fmt.Errorf("found %d folders, while expecting at most one", len(folderUIDs)) - } - - folderID := folderUIDs[0].ID - - if err := l.requireEditPermissionsOnFolder(c, signedInUser, folderID); err != nil { + if err := l.requireEditPermissionsOnFolderUID(c, signedInUser, folderUID); err != nil { + if errors.Is(err, dashboards.ErrDashboardNotFound) { + return dashboards.ErrFolderNotFound + } return err } var connectionIDs []struct { @@ -858,8 +843,8 @@ func (l *LibraryElementService) deleteLibraryElementsInFolderUID(c context.Conte } sql := "SELECT lec.connection_id FROM library_element AS le" sql += " INNER JOIN " + model.LibraryElementConnectionTableName + " AS lec on le.id = lec.element_id" - sql += " WHERE le.folder_id=? AND le.org_id=?" - err = session.SQL(sql, folderID, signedInUser.GetOrgID()).Find(&connectionIDs) + sql += " WHERE le.folder_uid=? AND le.org_id=?" + err := session.SQL(sql, folderUID, signedInUser.GetOrgID()).Find(&connectionIDs) if err != nil { return err } @@ -870,7 +855,7 @@ func (l *LibraryElementService) deleteLibraryElementsInFolderUID(c context.Conte var elementIDs []struct { ID int64 `xorm:"id"` } - err = session.SQL("SELECT id from library_element WHERE folder_id=? AND org_id=?", folderID, signedInUser.GetOrgID()).Find(&elementIDs) + err = session.SQL("SELECT id from library_element WHERE folder_uid=? AND org_id=?", folderUID, signedInUser.GetOrgID()).Find(&elementIDs) if err != nil { return err } @@ -880,7 +865,7 @@ func (l *LibraryElementService) deleteLibraryElementsInFolderUID(c context.Conte return err } } - if _, err := session.Exec("DELETE FROM library_element WHERE folder_id=? AND org_id=?", folderID, signedInUser.GetOrgID()); err != nil { + if _, err := session.Exec("DELETE FROM library_element WHERE folder_uid=? AND org_id=?", folderUID, signedInUser.GetOrgID()); err != nil { return err } diff --git a/pkg/services/libraryelements/guard.go b/pkg/services/libraryelements/guard.go index 38479965753..aa4f5d484fd 100644 --- a/pkg/services/libraryelements/guard.go +++ b/pkg/services/libraryelements/guard.go @@ -31,6 +31,32 @@ func (l *LibraryElementService) requireSupportedElementKind(kindAsInt int64) err } } +func (l *LibraryElementService) requireEditPermissionsOnFolderUID(ctx context.Context, user identity.Requester, folderUID string) error { + // TODO remove these special cases and handle General folder case in access control guardian + if isUIDGeneralFolder(folderUID) && user.HasRole(org.RoleEditor) { + return nil + } + + if isUIDGeneralFolder(folderUID) && user.HasRole(org.RoleViewer) { + return dashboards.ErrFolderAccessDenied + } + + g, err := guardian.NewByUID(ctx, folderUID, user.GetOrgID(), user) + if err != nil { + return err + } + + canEdit, err := g.CanEdit() + if err != nil { + return err + } + if !canEdit { + return dashboards.ErrFolderAccessDenied + } + + return nil +} + func (l *LibraryElementService) requireEditPermissionsOnFolder(ctx context.Context, user identity.Requester, folderID int64) error { // TODO remove these special cases and handle General folder case in access control guardian if isGeneralFolder(folderID) && user.HasRole(org.RoleEditor) {