Commit 86a7266f by Daniel Lee

dashfolders: handle permission changes when saving/moving dashboards

parent 30662802
...@@ -71,6 +71,11 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error { ...@@ -71,6 +71,11 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
} }
} }
err = setHasAcl(sess, dash)
if err != nil {
return err
}
parentVersion := dash.Version parentVersion := dash.Version
affectedRows := int64(0) affectedRows := int64(0)
...@@ -80,9 +85,9 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error { ...@@ -80,9 +85,9 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
dash.Data.Set("version", dash.Version) dash.Data.Set("version", dash.Version)
affectedRows, err = sess.Insert(dash) affectedRows, err = sess.Insert(dash)
} else { } else {
dash.Version += 1 dash.Version++
dash.Data.Set("version", dash.Version) dash.Data.Set("version", dash.Version)
affectedRows, err = sess.MustCols("folder_id").Id(dash.Id).Update(dash) affectedRows, err = sess.MustCols("folder_id", "has_acl").Id(dash.Id).Update(dash)
} }
if err != nil { if err != nil {
...@@ -111,7 +116,7 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error { ...@@ -111,7 +116,7 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
return m.ErrDashboardNotFound return m.ErrDashboardNotFound
} }
// delete existing tabs // delete existing tags
_, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.Id) _, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.Id)
if err != nil { if err != nil {
return err return err
...@@ -126,13 +131,37 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error { ...@@ -126,13 +131,37 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
} }
} }
} }
cmd.Result = dash cmd.Result = dash
return err return err
}) })
} }
func setHasAcl(sess *DBSession, dash *m.Dashboard) error {
// check if parent has acl
if dash.FolderId > 0 {
var parent m.Dashboard
if hasParent, err := sess.Where("folder_id=?", dash.FolderId).Get(&parent); err != nil {
return err
} else if hasParent && parent.HasAcl {
dash.HasAcl = true
}
}
// check if dash has its own acl
if dash.Id > 0 {
if res, err := sess.Query("SELECT 1 from dashboard_acl WHERE dashboard_id =?", dash.Id); err != nil {
return err
} else {
if len(res) > 0 {
dash.HasAcl = true
}
}
}
return nil
}
func GetDashboard(query *m.GetDashboardQuery) error { func GetDashboard(query *m.GetDashboardQuery) error {
dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id} dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id}
has, err := x.Get(&dashboard) has, err := x.Get(&dashboard)
......
...@@ -11,24 +11,6 @@ import ( ...@@ -11,24 +11,6 @@ import (
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
func insertTestDashboard(title string, orgId int64, folderId int64, isFolder bool, tags ...interface{}) *m.Dashboard {
cmd := m.SaveDashboardCommand{
OrgId: orgId,
FolderId: folderId,
IsFolder: isFolder,
Dashboard: simplejson.NewFromAny(map[string]interface{}{
"id": nil,
"title": title,
"tags": tags,
}),
}
err := SaveDashboard(&cmd)
So(err, ShouldBeNil)
return cmd.Result
}
func TestDashboardDataAccess(t *testing.T) { func TestDashboardDataAccess(t *testing.T) {
Convey("Testing DB", t, func() { Convey("Testing DB", t, func() {
...@@ -388,9 +370,99 @@ func TestDashboardDataAccess(t *testing.T) { ...@@ -388,9 +370,99 @@ func TestDashboardDataAccess(t *testing.T) {
}) })
}) })
}) })
Convey("Given two dashboard folders with one dashboard each and one dashboard in the root folder", func() {
folder1 := insertTestDashboard("1 test dash folder", 1, 0, true, "prod")
folder2 := insertTestDashboard("2 test dash folder", 1, 0, true, "prod")
dashInRoot := insertTestDashboard("test dash 67", 1, 0, false, "prod")
childDash1 := insertTestDashboard("child dash 1", 1, folder1.Id, false, "prod")
childDash2 := insertTestDashboard("child dash 2", 1, folder2.Id, false, "prod")
currentUser := createUser("viewer", "Viewer", false)
Convey("and acl is set for one dashboard folder", func() {
var otherUser int64 = 999
updateTestDashboardWithAcl(folder1.Id, otherUser, m.PERMISSION_EDIT)
Convey("and a dashboard is moved from folder without acl to the folder with an acl", func() {
movedDash := moveDashboard(1, childDash2.Data, folder1.Id)
So(movedDash.HasAcl, ShouldBeTrue)
Convey("should not return folder with acl or its children", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1},
OrgId: 1,
DashboardIds: []int64{folder1.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
}
err := SearchDashboards(query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1)
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},
OrgId: 1,
DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id},
}
err := SearchDashboards(query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 4)
So(query.Result[0].Id, ShouldEqual, folder2.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)
})
})
Convey("and a dashboard with an acl is moved to the folder without an acl", func() {
updateTestDashboardWithAcl(childDash1.Id, otherUser, m.PERMISSION_EDIT)
movedDash := moveDashboard(1, childDash1.Data, folder2.Id)
So(movedDash.HasAcl, ShouldBeTrue)
Convey("should return folder without acl but not the dashboard with acl", func() {
query := &search.FindPersistedDashboardsQuery{
SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1},
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(query.Result[0].Id, ShouldEqual, folder2.Id)
So(query.Result[1].Id, ShouldEqual, childDash2.Id)
So(query.Result[2].Id, ShouldEqual, dashInRoot.Id)
})
})
})
})
}) })
} }
func insertTestDashboard(title string, orgId int64, folderId int64, isFolder bool, tags ...interface{}) *m.Dashboard {
cmd := m.SaveDashboardCommand{
OrgId: orgId,
FolderId: folderId,
IsFolder: isFolder,
Dashboard: simplejson.NewFromAny(map[string]interface{}{
"id": nil,
"title": title,
"tags": tags,
}),
}
err := SaveDashboard(&cmd)
So(err, ShouldBeNil)
return cmd.Result
}
func createUser(name string, role string, isAdmin bool) m.User { func createUser(name string, role string, isAdmin bool) m.User {
setting.AutoAssignOrg = true setting.AutoAssignOrg = true
setting.AutoAssignOrgRole = role setting.AutoAssignOrgRole = role
...@@ -424,3 +496,17 @@ func removeAcl(aclId int64) { ...@@ -424,3 +496,17 @@ func removeAcl(aclId int64) {
err := RemoveDashboardAcl(&m.RemoveDashboardAclCommand{AclId: aclId, OrgId: 1}) err := RemoveDashboardAcl(&m.RemoveDashboardAclCommand{AclId: aclId, OrgId: 1})
So(err, ShouldBeNil) So(err, ShouldBeNil)
} }
func moveDashboard(orgId int64, dashboard *simplejson.Json, newFolderId int64) *m.Dashboard {
cmd := m.SaveDashboardCommand{
OrgId: orgId,
FolderId: newFolderId,
Dashboard: dashboard,
Overwrite: true,
}
err := SaveDashboard(&cmd)
So(err, ShouldBeNil)
return cmd.Result
}
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