Commit 8dd4d505 by Torkel Ödegaard

Merge branch 'dashboard-search-permissions-filter'

parents b60b6690 162439a8
...@@ -261,8 +261,6 @@ func (hs *HttpServer) registerRoutes() { ...@@ -261,8 +261,6 @@ func (hs *HttpServer) registerRoutes() {
dashboardRoute.Get("/tags", GetDashboardTags) dashboardRoute.Get("/tags", GetDashboardTags)
dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard)) dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
dashboardRoute.Get("/folders", wrap(GetFoldersForSignedInUser))
dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute RouteRegister) { dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute RouteRegister) {
dashIdRoute.Get("/versions", wrap(GetDashboardVersions)) dashIdRoute.Get("/versions", wrap(GetDashboardVersions))
dashIdRoute.Get("/versions/:id", wrap(GetDashboardVersion)) dashIdRoute.Get("/versions/:id", wrap(GetDashboardVersion))
......
...@@ -498,19 +498,3 @@ func GetDashboardTags(c *middleware.Context) { ...@@ -498,19 +498,3 @@ func GetDashboardTags(c *middleware.Context) {
c.JSON(200, query.Result) 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 ( ...@@ -6,6 +6,7 @@ import (
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/services/search"
) )
...@@ -15,11 +16,16 @@ func Search(c *middleware.Context) { ...@@ -15,11 +16,16 @@ func Search(c *middleware.Context) {
starred := c.Query("starred") starred := c.Query("starred")
limit := c.QueryInt("limit") limit := c.QueryInt("limit")
dashboardType := c.Query("type") dashboardType := c.Query("type")
permission := models.PERMISSION_VIEW
if limit == 0 { if limit == 0 {
limit = 1000 limit = 1000
} }
if c.Query("permission") == "Edit" {
permission = models.PERMISSION_EDIT
}
dbids := make([]int64, 0) dbids := make([]int64, 0)
for _, id := range c.QueryStrings("dashboardIds") { for _, id := range c.QueryStrings("dashboardIds") {
dashboardId, err := strconv.ParseInt(id, 10, 64) dashboardId, err := strconv.ParseInt(id, 10, 64)
...@@ -46,6 +52,7 @@ func Search(c *middleware.Context) { ...@@ -46,6 +52,7 @@ func Search(c *middleware.Context) {
DashboardIds: dbids, DashboardIds: dbids,
Type: dashboardType, Type: dashboardType,
FolderIds: folderIds, FolderIds: folderIds,
Permission: permission,
} }
err := bus.Dispatch(&searchQuery) err := bus.Dispatch(&searchQuery)
......
...@@ -304,18 +304,6 @@ type GetDashboardsBySlugQuery struct { ...@@ -304,18 +304,6 @@ type GetDashboardsBySlugQuery struct {
Result []*Dashboard 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 { type DashboardPermissionForUser struct {
DashboardId int64 `json:"dashboardId"` DashboardId int64 `json:"dashboardId"`
Permission PermissionType `json:"permission"` Permission PermissionType `json:"permission"`
......
...@@ -21,6 +21,7 @@ func searchHandler(query *Query) error { ...@@ -21,6 +21,7 @@ func searchHandler(query *Query) error {
FolderIds: query.FolderIds, FolderIds: query.FolderIds,
Tags: query.Tags, Tags: query.Tags,
Limit: query.Limit, Limit: query.Limit,
Permission: query.Permission,
} }
if err := bus.Dispatch(&dashQuery); err != nil { if err := bus.Dispatch(&dashQuery); err != nil {
......
...@@ -52,6 +52,7 @@ type Query struct { ...@@ -52,6 +52,7 @@ type Query struct {
Type string Type string
DashboardIds []int64 DashboardIds []int64
FolderIds []int64 FolderIds []int64
Permission models.PermissionType
Result HitList Result HitList
} }
...@@ -66,7 +67,7 @@ type FindPersistedDashboardsQuery struct { ...@@ -66,7 +67,7 @@ type FindPersistedDashboardsQuery struct {
FolderIds []int64 FolderIds []int64
Tags []string Tags []string
Limit int Limit int
IsBrowse bool Permission models.PermissionType
Result HitList Result HitList
} }
...@@ -21,7 +21,6 @@ func init() { ...@@ -21,7 +21,6 @@ func init() {
bus.AddHandler("sql", GetDashboardSlugById) bus.AddHandler("sql", GetDashboardSlugById)
bus.AddHandler("sql", GetDashboardUIDById) bus.AddHandler("sql", GetDashboardUIDById)
bus.AddHandler("sql", GetDashboardsByPluginId) bus.AddHandler("sql", GetDashboardsByPluginId)
bus.AddHandler("sql", GetFoldersForSignedInUser)
bus.AddHandler("sql", GetDashboardPermissionsForUser) bus.AddHandler("sql", GetDashboardPermissionsForUser)
bus.AddHandler("sql", GetDashboardsBySlug) bus.AddHandler("sql", GetDashboardsBySlug)
} }
...@@ -294,7 +293,7 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear ...@@ -294,7 +293,7 @@ func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSear
limit = 1000 limit = 1000
} }
sb := NewSearchBuilder(query.SignedInUser, limit). sb := NewSearchBuilder(query.SignedInUser, limit, query.Permission).
WithTags(query.Tags). WithTags(query.Tags).
WithDashboardIdsIn(query.DashboardIds) WithDashboardIdsIn(query.DashboardIds)
...@@ -395,54 +394,6 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error { ...@@ -395,54 +394,6 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
return err 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 { func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId} dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
......
...@@ -26,7 +26,11 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -26,7 +26,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("and no acls are set", func() { Convey("and no acls are set", func() {
Convey("should return all dashboards", 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) err := SearchDashboards(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)
...@@ -40,7 +44,10 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -40,7 +44,10 @@ func TestDashboardFolderDataAccess(t *testing.T) {
updateTestDashboardWithAcl(folder.Id, otherUser, m.PERMISSION_EDIT) updateTestDashboardWithAcl(folder.Id, otherUser, m.PERMISSION_EDIT)
Convey("should not return folder", func() { 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) err := SearchDashboards(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1) So(len(query.Result), ShouldEqual, 1)
...@@ -51,7 +58,11 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -51,7 +58,11 @@ func TestDashboardFolderDataAccess(t *testing.T) {
updateTestDashboardWithAcl(folder.Id, currentUser.Id, m.PERMISSION_EDIT) updateTestDashboardWithAcl(folder.Id, currentUser.Id, m.PERMISSION_EDIT)
Convey("should be able to access folder", func() { 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) err := SearchDashboards(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)
...@@ -87,7 +98,7 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -87,7 +98,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
updateTestDashboardWithAcl(childDash.Id, otherUser, m.PERMISSION_EDIT) updateTestDashboardWithAcl(childDash.Id, otherUser, m.PERMISSION_EDIT)
Convey("should not return folder or child", func() { 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) err := SearchDashboards(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1) So(len(query.Result), ShouldEqual, 1)
...@@ -98,7 +109,7 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -98,7 +109,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
updateTestDashboardWithAcl(childDash.Id, currentUser.Id, m.PERMISSION_EDIT) updateTestDashboardWithAcl(childDash.Id, currentUser.Id, m.PERMISSION_EDIT)
Convey("should be able to search for child dashboard but not folder", func() { 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) err := SearchDashboards(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)
...@@ -141,7 +152,7 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -141,7 +152,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("and one folder is expanded, the other collapsed", func() { Convey("and one folder is expanded, the other collapsed", func() {
Convey("should return dashboards in root and expanded folder", 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) err := SearchDashboards(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 4) So(len(query.Result), ShouldEqual, 4)
...@@ -162,7 +173,7 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -162,7 +173,7 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("should not return folder with acl or its children", func() { Convey("should not return folder with acl or its children", func() {
query := &search.FindPersistedDashboardsQuery{ 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, OrgId: 1,
DashboardIds: []int64{folder1.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, DashboardIds: []int64{folder1.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
} }
...@@ -172,14 +183,14 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -172,14 +183,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
So(query.Result[0].Id, ShouldEqual, dashInRoot.Id) 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() { Convey("and a dashboard is moved from folder with acl to the folder without an acl", func() {
movedDash := moveDashboard(1, childDash1.Data, folder2.Id) movedDash := moveDashboard(1, childDash1.Data, folder2.Id)
So(movedDash.HasAcl, ShouldBeFalse) So(movedDash.HasAcl, ShouldBeFalse)
Convey("should return folder without acl and its children", func() { Convey("should return folder without acl and its children", func() {
query := &search.FindPersistedDashboardsQuery{ 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, OrgId: 1,
DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
} }
...@@ -200,16 +211,17 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -200,16 +211,17 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("should return folder without acl but not the dashboard with acl", func() { Convey("should return folder without acl but not the dashboard with acl", func() {
query := &search.FindPersistedDashboardsQuery{ 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, OrgId: 1,
DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
} }
err := SearchDashboards(query) err := SearchDashboards(query)
So(err, ShouldBeNil) 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[0].Id, ShouldEqual, folder2.Id)
So(query.Result[1].Id, ShouldEqual, childDash2.Id) So(query.Result[1].Id, ShouldEqual, childDash1.Id)
So(query.Result[2].Id, ShouldEqual, dashInRoot.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) { ...@@ -227,12 +239,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
Convey("Admin users", func() { Convey("Admin users", func() {
Convey("Should have write access to all dashboard folders in their org", func() { Convey("Should have write access to all dashboard folders in their org", func() {
query := m.GetFoldersForSignedInUserQuery{ query := search.FindPersistedDashboardsQuery{
OrgId: 1, 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(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)
...@@ -260,13 +274,14 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -260,13 +274,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
}) })
Convey("Editor users", func() { Convey("Editor users", func() {
query := m.GetFoldersForSignedInUserQuery{ query := search.FindPersistedDashboardsQuery{
OrgId: 1, 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() { Convey("Should have write access to all dashboard folders with default ACL", func() {
err := GetFoldersForSignedInUser(&query) err := SearchDashboards(&query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)
...@@ -295,7 +310,7 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -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() { 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) updateTestDashboardWithAcl(folder1.Id, editorUser.Id, m.PERMISSION_VIEW)
err := GetFoldersForSignedInUser(&query) err := SearchDashboards(&query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1) So(len(query.Result), ShouldEqual, 1)
...@@ -305,13 +320,14 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -305,13 +320,14 @@ func TestDashboardFolderDataAccess(t *testing.T) {
}) })
Convey("Viewer users", func() { Convey("Viewer users", func() {
query := m.GetFoldersForSignedInUserQuery{ query := search.FindPersistedDashboardsQuery{
OrgId: 1, 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() { Convey("Should have no write access to any dashboard folders with default ACL", func() {
err := GetFoldersForSignedInUser(&query) err := SearchDashboards(&query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 0) So(len(query.Result), ShouldEqual, 0)
...@@ -338,7 +354,7 @@ func TestDashboardFolderDataAccess(t *testing.T) { ...@@ -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() { 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) updateTestDashboardWithAcl(folder1.Id, viewerUser.Id, m.PERMISSION_EDIT)
err := GetFoldersForSignedInUser(&query) err := SearchDashboards(&query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1) So(len(query.Result), ShouldEqual, 1)
......
...@@ -512,7 +512,7 @@ func TestDashboardDataAccess(t *testing.T) { ...@@ -512,7 +512,7 @@ func TestDashboardDataAccess(t *testing.T) {
query := search.FindPersistedDashboardsQuery{ query := search.FindPersistedDashboardsQuery{
Title: "1 test dash folder", Title: "1 test dash folder",
OrgId: 1, OrgId: 1,
SignedInUser: &m.SignedInUser{OrgId: 1}, SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR},
} }
err := SearchDashboards(&query) err := SearchDashboards(&query)
...@@ -529,7 +529,7 @@ func TestDashboardDataAccess(t *testing.T) { ...@@ -529,7 +529,7 @@ func TestDashboardDataAccess(t *testing.T) {
query := search.FindPersistedDashboardsQuery{ query := search.FindPersistedDashboardsQuery{
OrgId: 1, OrgId: 1,
FolderIds: []int64{savedFolder.Id}, FolderIds: []int64{savedFolder.Id},
SignedInUser: &m.SignedInUser{OrgId: 1}, SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR},
} }
err := SearchDashboards(&query) err := SearchDashboards(&query)
...@@ -549,7 +549,7 @@ func TestDashboardDataAccess(t *testing.T) { ...@@ -549,7 +549,7 @@ func TestDashboardDataAccess(t *testing.T) {
Convey("should be able to find two dashboards by id", func() { Convey("should be able to find two dashboards by id", func() {
query := search.FindPersistedDashboardsQuery{ query := search.FindPersistedDashboardsQuery{
DashboardIds: []int64{2, 3}, DashboardIds: []int64{2, 3},
SignedInUser: &m.SignedInUser{OrgId: 1}, SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR},
} }
err := SearchDashboards(&query) err := SearchDashboards(&query)
...@@ -578,7 +578,10 @@ func TestDashboardDataAccess(t *testing.T) { ...@@ -578,7 +578,10 @@ func TestDashboardDataAccess(t *testing.T) {
}) })
Convey("Should be able to search for starred dashboards", func() { 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) err := SearchDashboards(&query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
......
package sqlstore package sqlstore
import ( import (
"bytes"
"strings" "strings"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
...@@ -9,6 +8,7 @@ import ( ...@@ -9,6 +8,7 @@ import (
// SearchBuilder is a builder/object mother that builds a dashboard search query // SearchBuilder is a builder/object mother that builds a dashboard search query
type SearchBuilder struct { type SearchBuilder struct {
SqlBuilder
tags []string tags []string
isStarred bool isStarred bool
limit int limit int
...@@ -18,14 +18,14 @@ type SearchBuilder struct { ...@@ -18,14 +18,14 @@ type SearchBuilder struct {
whereTypeFolder bool whereTypeFolder bool
whereTypeDash bool whereTypeDash bool
whereFolderIds []int64 whereFolderIds []int64
sql bytes.Buffer permission m.PermissionType
params []interface{}
} }
func NewSearchBuilder(signedInUser *m.SignedInUser, limit int) *SearchBuilder { func NewSearchBuilder(signedInUser *m.SignedInUser, limit int, permission m.PermissionType) *SearchBuilder {
searchBuilder := &SearchBuilder{ searchBuilder := &SearchBuilder{
signedInUser: signedInUser, signedInUser: signedInUser,
limit: limit, limit: limit,
permission: permission,
} }
return searchBuilder return searchBuilder
...@@ -153,10 +153,7 @@ func (sb *SearchBuilder) buildMainQuery() { ...@@ -153,10 +153,7 @@ func (sb *SearchBuilder) buildMainQuery() {
sb.sql.WriteString(` WHERE `) sb.sql.WriteString(` WHERE `)
sb.buildSearchWhereClause() sb.buildSearchWhereClause()
sb.sql.WriteString(` sb.sql.WriteString(` LIMIT ?) as ids INNER JOIN dashboard on ids.id = dashboard.id `)
LIMIT ?) as ids
INNER JOIN dashboard on ids.id = dashboard.id
`)
sb.params = append(sb.params, sb.limit) sb.params = append(sb.params, sb.limit)
} }
...@@ -176,23 +173,7 @@ func (sb *SearchBuilder) buildSearchWhereClause() { ...@@ -176,23 +173,7 @@ func (sb *SearchBuilder) buildSearchWhereClause() {
} }
} }
if sb.signedInUser.OrgRole != m.ROLE_ADMIN { sb.writeDashboardPermissionFilter(sb.signedInUser, sb.permission)
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)
}
if len(sb.whereTitle) > 0 { if len(sb.whereTitle) > 0 {
sb.sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?") sb.sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?")
......
...@@ -16,7 +16,8 @@ func TestSearchBuilder(t *testing.T) { ...@@ -16,7 +16,8 @@ func TestSearchBuilder(t *testing.T) {
OrgId: 1, OrgId: 1,
UserId: 1, UserId: 1,
} }
sb := NewSearchBuilder(signedInUser, 1000)
sb := NewSearchBuilder(signedInUser, 1000, m.PERMISSION_VIEW)
Convey("When building a normal search", func() { Convey("When building a normal search", func() {
sql, params := sb.IsStarred().WithTitle("test").ToSql() sql, params := sb.IsStarred().WithTitle("test").ToSql()
......
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 { ...@@ -30,7 +30,13 @@ export class FolderPickerCtrl {
} }
getOptions(query) { 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 ( if (
query === '' || query === '' ||
query.toLowerCase() === 'g' || query.toLowerCase() === 'g' ||
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment