mirror of
https://github.com/grafana/grafana.git
synced 2025-08-03 04:22:13 +08:00
Merge branch 'dashboard-search-permissions-filter'
This commit is contained in:
@ -261,8 +261,6 @@ func (hs *HttpServer) registerRoutes() {
|
||||
dashboardRoute.Get("/tags", GetDashboardTags)
|
||||
dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
|
||||
|
||||
dashboardRoute.Get("/folders", wrap(GetFoldersForSignedInUser))
|
||||
|
||||
dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute RouteRegister) {
|
||||
dashIdRoute.Get("/versions", wrap(GetDashboardVersions))
|
||||
dashIdRoute.Get("/versions/:id", wrap(GetDashboardVersion))
|
||||
|
@ -498,19 +498,3 @@ func GetDashboardTags(c *middleware.Context) {
|
||||
|
||||
c.JSON(200, query.Result)
|
||||
}
|
||||
|
||||
func GetFoldersForSignedInUser(c *middleware.Context) Response {
|
||||
title := c.Query("query")
|
||||
query := m.GetFoldersForSignedInUserQuery{
|
||||
OrgId: c.OrgId,
|
||||
SignedInUser: c.SignedInUser,
|
||||
Title: title,
|
||||
}
|
||||
|
||||
err := bus.Dispatch(&query)
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to get folders from database", err)
|
||||
}
|
||||
|
||||
return Json(200, query.Result)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/metrics"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/search"
|
||||
)
|
||||
|
||||
@ -15,11 +16,16 @@ func Search(c *middleware.Context) {
|
||||
starred := c.Query("starred")
|
||||
limit := c.QueryInt("limit")
|
||||
dashboardType := c.Query("type")
|
||||
permission := models.PERMISSION_VIEW
|
||||
|
||||
if limit == 0 {
|
||||
limit = 1000
|
||||
}
|
||||
|
||||
if c.Query("permission") == "Edit" {
|
||||
permission = models.PERMISSION_EDIT
|
||||
}
|
||||
|
||||
dbids := make([]int64, 0)
|
||||
for _, id := range c.QueryStrings("dashboardIds") {
|
||||
dashboardId, err := strconv.ParseInt(id, 10, 64)
|
||||
@ -46,6 +52,7 @@ func Search(c *middleware.Context) {
|
||||
DashboardIds: dbids,
|
||||
Type: dashboardType,
|
||||
FolderIds: folderIds,
|
||||
Permission: permission,
|
||||
}
|
||||
|
||||
err := bus.Dispatch(&searchQuery)
|
||||
|
@ -304,18 +304,6 @@ type GetDashboardsBySlugQuery struct {
|
||||
Result []*Dashboard
|
||||
}
|
||||
|
||||
type GetFoldersForSignedInUserQuery struct {
|
||||
OrgId int64
|
||||
SignedInUser *SignedInUser
|
||||
Title string
|
||||
Result []*DashboardFolder
|
||||
}
|
||||
|
||||
type DashboardFolder struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type DashboardPermissionForUser struct {
|
||||
DashboardId int64 `json:"dashboardId"`
|
||||
Permission PermissionType `json:"permission"`
|
||||
|
@ -21,6 +21,7 @@ func searchHandler(query *Query) error {
|
||||
FolderIds: query.FolderIds,
|
||||
Tags: query.Tags,
|
||||
Limit: query.Limit,
|
||||
Permission: query.Permission,
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&dashQuery); err != nil {
|
||||
|
@ -52,6 +52,7 @@ type Query struct {
|
||||
Type string
|
||||
DashboardIds []int64
|
||||
FolderIds []int64
|
||||
Permission models.PermissionType
|
||||
|
||||
Result HitList
|
||||
}
|
||||
@ -66,7 +67,7 @@ type FindPersistedDashboardsQuery struct {
|
||||
FolderIds []int64
|
||||
Tags []string
|
||||
Limit int
|
||||
IsBrowse bool
|
||||
Permission models.PermissionType
|
||||
|
||||
Result HitList
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ func init() {
|
||||
bus.AddHandler("sql", GetDashboardSlugById)
|
||||
bus.AddHandler("sql", GetDashboardUIDById)
|
||||
bus.AddHandler("sql", GetDashboardsByPluginId)
|
||||
bus.AddHandler("sql", GetFoldersForSignedInUser)
|
||||
bus.AddHandler("sql", GetDashboardPermissionsForUser)
|
||||
bus.AddHandler("sql", GetDashboardsBySlug)
|
||||
}
|
||||
@ -294,7 +293,7 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear
|
||||
limit = 1000
|
||||
}
|
||||
|
||||
sb := NewSearchBuilder(query.SignedInUser, limit).
|
||||
sb := NewSearchBuilder(query.SignedInUser, limit, query.Permission).
|
||||
WithTags(query.Tags).
|
||||
WithDashboardIdsIn(query.DashboardIds)
|
||||
|
||||
@ -395,54 +394,6 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func GetFoldersForSignedInUser(query *m.GetFoldersForSignedInUserQuery) error {
|
||||
query.Result = make([]*m.DashboardFolder, 0)
|
||||
var err error
|
||||
|
||||
if query.SignedInUser.OrgRole == m.ROLE_ADMIN {
|
||||
sql := `SELECT distinct d.id, d.title
|
||||
FROM dashboard AS d WHERE d.is_folder = ? AND d.org_id = ?
|
||||
ORDER BY d.title ASC`
|
||||
|
||||
err = x.Sql(sql, dialect.BooleanStr(true), query.OrgId).Find(&query.Result)
|
||||
} else {
|
||||
params := make([]interface{}, 0)
|
||||
sql := `SELECT distinct d.id, d.title
|
||||
FROM dashboard AS d
|
||||
LEFT JOIN dashboard_acl AS da ON d.id = da.dashboard_id
|
||||
LEFT JOIN team_member AS ugm ON ugm.team_id = da.team_id
|
||||
LEFT JOIN org_user ou ON ou.role = da.role AND ou.user_id = ?
|
||||
LEFT JOIN org_user ouRole ON ouRole.role = 'Editor' AND ouRole.user_id = ? AND ouRole.org_id = ?`
|
||||
params = append(params, query.SignedInUser.UserId)
|
||||
params = append(params, query.SignedInUser.UserId)
|
||||
params = append(params, query.OrgId)
|
||||
|
||||
sql += ` WHERE
|
||||
d.org_id = ? AND
|
||||
d.is_folder = ? AND
|
||||
(
|
||||
(d.has_acl = ? AND da.permission > 1 AND (da.user_id = ? OR ugm.user_id = ? OR ou.id IS NOT NULL))
|
||||
OR (d.has_acl = ? AND ouRole.id IS NOT NULL)
|
||||
)`
|
||||
params = append(params, query.OrgId)
|
||||
params = append(params, dialect.BooleanStr(true))
|
||||
params = append(params, dialect.BooleanStr(true))
|
||||
params = append(params, query.SignedInUser.UserId)
|
||||
params = append(params, query.SignedInUser.UserId)
|
||||
params = append(params, dialect.BooleanStr(false))
|
||||
|
||||
if len(query.Title) > 0 {
|
||||
sql += " AND d.title " + dialect.LikeStr() + " ?"
|
||||
params = append(params, "%"+query.Title+"%")
|
||||
}
|
||||
|
||||
sql += ` ORDER BY d.title ASC`
|
||||
err = x.Sql(sql, params...).Find(&query.Result)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
|
||||
|
@ -26,7 +26,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
|
||||
Convey("and no acls are set", func() {
|
||||
Convey("should return all dashboards", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1}, OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id}}
|
||||
query := &search.FindPersistedDashboardsQuery{
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
|
||||
OrgId: 1,
|
||||
DashboardIds: []int64{folder.Id, dashInRoot.Id},
|
||||
}
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
@ -40,7 +44,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
updateTestDashboardWithAcl(folder.Id, otherUser, m.PERMISSION_EDIT)
|
||||
|
||||
Convey("should not return folder", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1}, OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id}}
|
||||
query := &search.FindPersistedDashboardsQuery{
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
|
||||
OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id},
|
||||
}
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
@ -51,7 +58,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
updateTestDashboardWithAcl(folder.Id, currentUser.Id, m.PERMISSION_EDIT)
|
||||
|
||||
Convey("should be able to access folder", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1}, OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id}}
|
||||
query := &search.FindPersistedDashboardsQuery{
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
|
||||
OrgId: 1,
|
||||
DashboardIds: []int64{folder.Id, dashInRoot.Id},
|
||||
}
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
@ -87,7 +98,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
updateTestDashboardWithAcl(childDash.Id, otherUser, m.PERMISSION_EDIT)
|
||||
|
||||
Convey("should not return folder or child", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}}
|
||||
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}}
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
@ -98,7 +109,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
updateTestDashboardWithAcl(childDash.Id, currentUser.Id, m.PERMISSION_EDIT)
|
||||
|
||||
Convey("should be able to search for child dashboard but not folder", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}}
|
||||
query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}}
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
@ -141,7 +152,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
|
||||
Convey("and one folder is expanded, the other collapsed", func() {
|
||||
Convey("should return dashboards in root and expanded folder", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{FolderIds: []int64{rootFolderId, folder1.Id}, SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1}, OrgId: 1}
|
||||
query := &search.FindPersistedDashboardsQuery{FolderIds: []int64{rootFolderId, folder1.Id}, SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1}
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 4)
|
||||
@ -162,7 +173,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
|
||||
Convey("should not return folder with acl or its children", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1},
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
|
||||
OrgId: 1,
|
||||
DashboardIds: []int64{folder1.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
|
||||
}
|
||||
@ -172,14 +183,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
So(query.Result[0].Id, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("and a dashboard is moved from folder with acl to the folder without an acl", func() {
|
||||
|
||||
movedDash := moveDashboard(1, childDash1.Data, folder2.Id)
|
||||
So(movedDash.HasAcl, ShouldBeFalse)
|
||||
|
||||
Convey("should return folder without acl and its children", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1},
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
|
||||
OrgId: 1,
|
||||
DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
|
||||
}
|
||||
@ -200,16 +211,17 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
|
||||
Convey("should return folder without acl but not the dashboard with acl", func() {
|
||||
query := &search.FindPersistedDashboardsQuery{
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1},
|
||||
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER},
|
||||
OrgId: 1,
|
||||
DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
|
||||
}
|
||||
err := SearchDashboards(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 3)
|
||||
So(len(query.Result), ShouldEqual, 4)
|
||||
So(query.Result[0].Id, ShouldEqual, folder2.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, childDash2.Id)
|
||||
So(query.Result[2].Id, ShouldEqual, dashInRoot.Id)
|
||||
So(query.Result[1].Id, ShouldEqual, childDash1.Id)
|
||||
So(query.Result[2].Id, ShouldEqual, childDash2.Id)
|
||||
So(query.Result[3].Id, ShouldEqual, dashInRoot.Id)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -227,12 +239,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
|
||||
Convey("Admin users", func() {
|
||||
Convey("Should have write access to all dashboard folders in their org", func() {
|
||||
query := m.GetFoldersForSignedInUserQuery{
|
||||
query := search.FindPersistedDashboardsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &m.SignedInUser{UserId: adminUser.Id, OrgRole: m.ROLE_ADMIN},
|
||||
SignedInUser: &m.SignedInUser{UserId: adminUser.Id, OrgRole: m.ROLE_ADMIN, OrgId: 1},
|
||||
Permission: m.PERMISSION_VIEW,
|
||||
Type: "dash-folder",
|
||||
}
|
||||
|
||||
err := GetFoldersForSignedInUser(&query)
|
||||
err := SearchDashboards(&query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
@ -260,13 +274,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Editor users", func() {
|
||||
query := m.GetFoldersForSignedInUserQuery{
|
||||
query := search.FindPersistedDashboardsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &m.SignedInUser{UserId: editorUser.Id, OrgRole: m.ROLE_EDITOR},
|
||||
SignedInUser: &m.SignedInUser{UserId: editorUser.Id, OrgRole: m.ROLE_EDITOR, OrgId: 1},
|
||||
Permission: m.PERMISSION_EDIT,
|
||||
}
|
||||
|
||||
Convey("Should have write access to all dashboard folders with default ACL", func() {
|
||||
err := GetFoldersForSignedInUser(&query)
|
||||
err := SearchDashboards(&query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
@ -295,7 +310,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
Convey("Should have write access to one dashboard folder if default role changed to view for one folder", func() {
|
||||
updateTestDashboardWithAcl(folder1.Id, editorUser.Id, m.PERMISSION_VIEW)
|
||||
|
||||
err := GetFoldersForSignedInUser(&query)
|
||||
err := SearchDashboards(&query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
@ -305,13 +320,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Viewer users", func() {
|
||||
query := m.GetFoldersForSignedInUserQuery{
|
||||
query := search.FindPersistedDashboardsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgRole: m.ROLE_VIEWER},
|
||||
SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgRole: m.ROLE_VIEWER, OrgId: 1},
|
||||
Permission: m.PERMISSION_EDIT,
|
||||
}
|
||||
|
||||
Convey("Should have no write access to any dashboard folders with default ACL", func() {
|
||||
err := GetFoldersForSignedInUser(&query)
|
||||
err := SearchDashboards(&query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 0)
|
||||
@ -338,7 +354,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
|
||||
Convey("Should be able to get one dashboard folder if default role changed to edit for one folder", func() {
|
||||
updateTestDashboardWithAcl(folder1.Id, viewerUser.Id, m.PERMISSION_EDIT)
|
||||
|
||||
err := GetFoldersForSignedInUser(&query)
|
||||
err := SearchDashboards(&query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
|
@ -512,7 +512,7 @@ func TestDashboardDataAccess(t *testing.T) {
|
||||
query := search.FindPersistedDashboardsQuery{
|
||||
Title: "1 test dash folder",
|
||||
OrgId: 1,
|
||||
SignedInUser: &m.SignedInUser{OrgId: 1},
|
||||
SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR},
|
||||
}
|
||||
|
||||
err := SearchDashboards(&query)
|
||||
@ -529,7 +529,7 @@ func TestDashboardDataAccess(t *testing.T) {
|
||||
query := search.FindPersistedDashboardsQuery{
|
||||
OrgId: 1,
|
||||
FolderIds: []int64{savedFolder.Id},
|
||||
SignedInUser: &m.SignedInUser{OrgId: 1},
|
||||
SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR},
|
||||
}
|
||||
|
||||
err := SearchDashboards(&query)
|
||||
@ -549,7 +549,7 @@ func TestDashboardDataAccess(t *testing.T) {
|
||||
Convey("should be able to find two dashboards by id", func() {
|
||||
query := search.FindPersistedDashboardsQuery{
|
||||
DashboardIds: []int64{2, 3},
|
||||
SignedInUser: &m.SignedInUser{OrgId: 1},
|
||||
SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR},
|
||||
}
|
||||
|
||||
err := SearchDashboards(&query)
|
||||
@ -578,7 +578,10 @@ func TestDashboardDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Should be able to search for starred dashboards", func() {
|
||||
query := search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: 10, OrgId: 1}, IsStarred: true}
|
||||
query := search.FindPersistedDashboardsQuery{
|
||||
SignedInUser: &m.SignedInUser{UserId: 10, OrgId: 1, OrgRole: m.ROLE_EDITOR},
|
||||
IsStarred: true,
|
||||
}
|
||||
err := SearchDashboards(&query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
@ -9,6 +8,7 @@ import (
|
||||
|
||||
// SearchBuilder is a builder/object mother that builds a dashboard search query
|
||||
type SearchBuilder struct {
|
||||
SqlBuilder
|
||||
tags []string
|
||||
isStarred bool
|
||||
limit int
|
||||
@ -18,14 +18,14 @@ type SearchBuilder struct {
|
||||
whereTypeFolder bool
|
||||
whereTypeDash bool
|
||||
whereFolderIds []int64
|
||||
sql bytes.Buffer
|
||||
params []interface{}
|
||||
permission m.PermissionType
|
||||
}
|
||||
|
||||
func NewSearchBuilder(signedInUser *m.SignedInUser, limit int) *SearchBuilder {
|
||||
func NewSearchBuilder(signedInUser *m.SignedInUser, limit int, permission m.PermissionType) *SearchBuilder {
|
||||
searchBuilder := &SearchBuilder{
|
||||
signedInUser: signedInUser,
|
||||
limit: limit,
|
||||
permission: permission,
|
||||
}
|
||||
|
||||
return searchBuilder
|
||||
@ -153,10 +153,7 @@ func (sb *SearchBuilder) buildMainQuery() {
|
||||
sb.sql.WriteString(` WHERE `)
|
||||
sb.buildSearchWhereClause()
|
||||
|
||||
sb.sql.WriteString(`
|
||||
LIMIT ?) as ids
|
||||
INNER JOIN dashboard on ids.id = dashboard.id
|
||||
`)
|
||||
sb.sql.WriteString(` LIMIT ?) as ids INNER JOIN dashboard on ids.id = dashboard.id `)
|
||||
sb.params = append(sb.params, sb.limit)
|
||||
}
|
||||
|
||||
@ -176,23 +173,7 @@ func (sb *SearchBuilder) buildSearchWhereClause() {
|
||||
}
|
||||
}
|
||||
|
||||
if sb.signedInUser.OrgRole != m.ROLE_ADMIN {
|
||||
allowedDashboardsSubQuery := ` AND (dashboard.has_acl = ` + dialect.BooleanStr(false) + ` OR dashboard.id in (
|
||||
SELECT distinct d.id AS DashboardId
|
||||
FROM dashboard AS d
|
||||
LEFT JOIN dashboard_acl as da on d.folder_id = da.dashboard_id or d.id = da.dashboard_id
|
||||
LEFT JOIN team_member as ugm on ugm.team_id = da.team_id
|
||||
LEFT JOIN org_user ou on ou.role = da.role
|
||||
WHERE
|
||||
d.has_acl = ` + dialect.BooleanStr(true) + ` and
|
||||
(da.user_id = ? or ugm.user_id = ? or ou.id is not null)
|
||||
and d.org_id = ?
|
||||
)
|
||||
)`
|
||||
|
||||
sb.sql.WriteString(allowedDashboardsSubQuery)
|
||||
sb.params = append(sb.params, sb.signedInUser.UserId, sb.signedInUser.UserId, sb.signedInUser.OrgId)
|
||||
}
|
||||
sb.writeDashboardPermissionFilter(sb.signedInUser, sb.permission)
|
||||
|
||||
if len(sb.whereTitle) > 0 {
|
||||
sb.sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?")
|
||||
|
@ -16,7 +16,8 @@ func TestSearchBuilder(t *testing.T) {
|
||||
OrgId: 1,
|
||||
UserId: 1,
|
||||
}
|
||||
sb := NewSearchBuilder(signedInUser, 1000)
|
||||
|
||||
sb := NewSearchBuilder(signedInUser, 1000, m.PERMISSION_VIEW)
|
||||
|
||||
Convey("When building a normal search", func() {
|
||||
sql, params := sb.IsStarred().WithTitle("test").ToSql()
|
||||
|
59
pkg/services/sqlstore/sqlbuilder.go
Normal file
59
pkg/services/sqlstore/sqlbuilder.go
Normal file
@ -0,0 +1,59 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type SqlBuilder struct {
|
||||
sql bytes.Buffer
|
||||
params []interface{}
|
||||
}
|
||||
|
||||
func (sb *SqlBuilder) writeDashboardPermissionFilter(user *m.SignedInUser, permission m.PermissionType) {
|
||||
|
||||
if user.OrgRole == m.ROLE_ADMIN {
|
||||
return
|
||||
}
|
||||
|
||||
okRoles := []interface{}{user.OrgRole}
|
||||
|
||||
if user.OrgRole == m.ROLE_EDITOR {
|
||||
okRoles = append(okRoles, m.ROLE_VIEWER)
|
||||
}
|
||||
|
||||
falseStr := dialect.BooleanStr(false)
|
||||
|
||||
sb.sql.WriteString(` AND
|
||||
(
|
||||
dashboard.id IN (
|
||||
SELECT distinct d.id AS DashboardId
|
||||
FROM dashboard AS d
|
||||
LEFT JOIN dashboard folder on folder.id = d.folder_id
|
||||
LEFT JOIN dashboard_acl AS da ON
|
||||
da.dashboard_id = d.id OR
|
||||
da.dashboard_id = d.folder_id OR
|
||||
(
|
||||
-- include default permissions -->
|
||||
da.org_id = -1 AND (
|
||||
(folder.id IS NOT NULL AND folder.has_acl = ` + falseStr + `) OR
|
||||
(folder.id IS NULL AND d.has_acl = ` + falseStr + `)
|
||||
)
|
||||
)
|
||||
LEFT JOIN team_member as ugm on ugm.team_id = da.team_id
|
||||
WHERE
|
||||
d.org_id = ? AND
|
||||
da.permission >= ? AND
|
||||
(
|
||||
da.user_id = ? OR
|
||||
ugm.user_id = ? OR
|
||||
da.role IN (?` + strings.Repeat(",?", len(okRoles)-1) + `)
|
||||
)
|
||||
)
|
||||
)`)
|
||||
|
||||
sb.params = append(sb.params, user.OrgId, permission, user.UserId, user.UserId)
|
||||
sb.params = append(sb.params, okRoles...)
|
||||
}
|
@ -30,7 +30,13 @@ export class FolderPickerCtrl {
|
||||
}
|
||||
|
||||
getOptions(query) {
|
||||
return this.backendSrv.get('api/dashboards/folders', { query: query }).then(result => {
|
||||
const params = {
|
||||
query: query,
|
||||
type: 'dash-folder',
|
||||
permission: 'Edit',
|
||||
};
|
||||
|
||||
return this.backendSrv.get('api/search', params).then(result => {
|
||||
if (
|
||||
query === '' ||
|
||||
query.toLowerCase() === 'g' ||
|
||||
|
Reference in New Issue
Block a user