LibraryPanels: Adds folder checks and permissions (#31473)
* Refactor: adds permissions for library panel creation * Refactor: checks folder permissions for patch requests * Chore: changes after PR comments * Refactor: adds permissions to delete * Refactor: moves get all permission tests out of get all tests * Chore: move out get all tests to a separate file * Refactor: adds permissions to get handler * Refactor: fixes a bug with getting library panels in General folder * Refactor: adds permissions for connect/disconnect * Refactor: adds permissions and tests for get connected dashboards * Tests: adds tests for connected dashboards in General Folder
This commit is contained in:
@@ -66,6 +66,9 @@ func (lps *LibraryPanelService) createLibraryPanel(c *models.ReqContext, cmd cre
|
||||
}
|
||||
|
||||
err := lps.SQLStore.WithTransactionalDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error {
|
||||
if err := requirePermissionsOnFolder(c.SignedInUser, cmd.FolderID); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := session.Insert(&libraryPanel); err != nil {
|
||||
if lps.SQLStore.Dialect.IsUniqueConstraintViolation(err) {
|
||||
return errLibraryPanelAlreadyExists
|
||||
@@ -108,6 +111,9 @@ func connectDashboard(session *sqlstore.DBSession, dialect migrator.Dialect, use
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := requirePermissionsOnFolder(user, panel.FolderID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO add check that dashboard exists
|
||||
|
||||
@@ -161,7 +167,9 @@ func (lps *LibraryPanelService) deleteLibraryPanel(c *models.ReqContext, uid str
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := requirePermissionsOnFolder(c.SignedInUser, panel.FolderID); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := session.Exec("DELETE FROM library_panel_dashboard WHERE librarypanel_id=?", panel.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -187,6 +195,9 @@ func (lps *LibraryPanelService) disconnectDashboard(c *models.ReqContext, uid st
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := requirePermissionsOnFolder(c.SignedInUser, panel.FolderID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := session.Exec("DELETE FROM library_panel_dashboard WHERE librarypanel_id=? and dashboard_id=?", panel.ID, dashboardID)
|
||||
if err != nil {
|
||||
@@ -242,9 +253,31 @@ func getLibraryPanel(session *sqlstore.DBSession, uid string, orgID int64) (Libr
|
||||
func (lps *LibraryPanelService) getLibraryPanel(c *models.ReqContext, uid string) (LibraryPanelDTO, error) {
|
||||
var libraryPanel LibraryPanelWithMeta
|
||||
err := lps.SQLStore.WithDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error {
|
||||
var err error
|
||||
libraryPanel, err = getLibraryPanel(session, uid, c.SignedInUser.OrgId)
|
||||
return err
|
||||
libraryPanels := make([]LibraryPanelWithMeta, 0)
|
||||
builder := sqlstore.SQLBuilder{}
|
||||
builder.Write(sqlStatmentLibrayPanelDTOWithMeta)
|
||||
builder.Write(` WHERE lp.uid=? AND lp.org_id=? AND lp.folder_id=0`, uid, c.SignedInUser.OrgId)
|
||||
builder.Write(" UNION ")
|
||||
builder.Write(sqlStatmentLibrayPanelDTOWithMeta)
|
||||
builder.Write(" INNER JOIN dashboard AS dashboard on lp.folder_id = dashboard.id AND lp.folder_id <> 0")
|
||||
builder.Write(` WHERE lp.uid=? AND lp.org_id=?`, uid, c.SignedInUser.OrgId)
|
||||
if c.SignedInUser.OrgRole != models.ROLE_ADMIN {
|
||||
builder.WriteDashboardPermissionFilter(c.SignedInUser, models.PERMISSION_VIEW)
|
||||
}
|
||||
builder.Write(` OR dashboard.id=0`)
|
||||
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryPanels); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(libraryPanels) == 0 {
|
||||
return errLibraryPanelNotFound
|
||||
}
|
||||
if len(libraryPanels) > 1 {
|
||||
return fmt.Errorf("found %d panels, while expecting at most one", len(libraryPanels))
|
||||
}
|
||||
|
||||
libraryPanel = libraryPanels[0]
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
dto := LibraryPanelDTO{
|
||||
@@ -281,8 +314,11 @@ func (lps *LibraryPanelService) getAllLibraryPanels(c *models.ReqContext, limit
|
||||
err := lps.SQLStore.WithDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error {
|
||||
builder := sqlstore.SQLBuilder{}
|
||||
builder.Write(sqlStatmentLibrayPanelDTOWithMeta)
|
||||
builder.Write(" LEFT JOIN dashboard AS dashboard on lp.folder_id = dashboard.id")
|
||||
builder.Write(` WHERE lp.org_id = ?`, c.SignedInUser.OrgId)
|
||||
builder.Write(` WHERE lp.org_id=? AND lp.folder_id=0`, c.SignedInUser.OrgId)
|
||||
builder.Write(" UNION ")
|
||||
builder.Write(sqlStatmentLibrayPanelDTOWithMeta)
|
||||
builder.Write(" INNER JOIN dashboard AS dashboard on lp.folder_id = dashboard.id AND lp.folder_id<>0")
|
||||
builder.Write(` WHERE lp.org_id=?`, c.SignedInUser.OrgId)
|
||||
if c.SignedInUser.OrgRole != models.ROLE_ADMIN {
|
||||
builder.WriteDashboardPermissionFilter(c.SignedInUser, models.PERMISSION_VIEW)
|
||||
}
|
||||
@@ -336,12 +372,15 @@ func (lps *LibraryPanelService) getConnectedDashboards(c *models.ReqContext, uid
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var libraryPanelDashboards []libraryPanelDashboard
|
||||
session.Table("library_panel_dashboard")
|
||||
session.Where("librarypanel_id=?", panel.ID)
|
||||
err = session.Find(&libraryPanelDashboards)
|
||||
if err != nil {
|
||||
builder := sqlstore.SQLBuilder{}
|
||||
builder.Write("SELECT lpd.* FROM library_panel_dashboard lpd")
|
||||
builder.Write(" INNER JOIN dashboard AS dashboard on lpd.dashboard_id = dashboard.id")
|
||||
builder.Write(` WHERE lpd.librarypanel_id=?`, panel.ID)
|
||||
if c.SignedInUser.OrgRole != models.ROLE_ADMIN {
|
||||
builder.WriteDashboardPermissionFilter(c.SignedInUser, models.PERMISSION_VIEW)
|
||||
}
|
||||
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryPanelDashboards); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -399,6 +438,29 @@ func (lps *LibraryPanelService) getLibraryPanelsForDashboardID(c *models.ReqCont
|
||||
return libraryPanelMap, err
|
||||
}
|
||||
|
||||
func handleFolderIDPatches(panelToPatch *LibraryPanel, fromFolderID int64, toFolderID int64, user *models.SignedInUser) error {
|
||||
// FolderID was not provided in the PATCH request
|
||||
if toFolderID == -1 {
|
||||
toFolderID = fromFolderID
|
||||
}
|
||||
|
||||
// FolderID was provided in the PATCH request
|
||||
if toFolderID != -1 && toFolderID != fromFolderID {
|
||||
if err := requirePermissionsOnFolder(user, toFolderID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Always check permissions for the folder where library panel resides
|
||||
if err := requirePermissionsOnFolder(user, fromFolderID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
panelToPatch.FolderID = toFolderID
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// patchLibraryPanel updates a Library Panel.
|
||||
func (lps *LibraryPanelService) patchLibraryPanel(c *models.ReqContext, cmd patchLibraryPanelCommand, uid string) (LibraryPanelDTO, error) {
|
||||
var dto LibraryPanelDTO
|
||||
@@ -421,19 +483,18 @@ func (lps *LibraryPanelService) patchLibraryPanel(c *models.ReqContext, cmd patc
|
||||
UpdatedBy: c.SignedInUser.UserId,
|
||||
}
|
||||
|
||||
if cmd.FolderID == 0 {
|
||||
libraryPanel.FolderID = panelInDB.FolderID
|
||||
}
|
||||
if cmd.Name == "" {
|
||||
libraryPanel.Name = panelInDB.Name
|
||||
}
|
||||
if cmd.Model == nil {
|
||||
libraryPanel.Model = panelInDB.Model
|
||||
}
|
||||
if err := handleFolderIDPatches(&libraryPanel, panelInDB.FolderID, cmd.FolderID, c.SignedInUser); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := syncTitleWithName(&libraryPanel); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rowsAffected, err := session.ID(panelInDB.ID).Update(&libraryPanel); err != nil {
|
||||
if lps.SQLStore.Dialect.IsUniqueConstraintViolation(err) {
|
||||
return errLibraryPanelAlreadyExists
|
||||
|
||||
Reference in New Issue
Block a user