Browse Source

dashfolders: handle permission changes when saving/moving dashboards

Daniel Lee 8 years ago
parent
commit
86a7266f5f
2 changed files with 137 additions and 22 deletions
  1. 33 4
      pkg/services/sqlstore/dashboard.go
  2. 104 18
      pkg/services/sqlstore/dashboard_test.go

+ 33 - 4
pkg/services/sqlstore/dashboard.go

@@ -71,6 +71,11 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
 			}
 		}
 
+		err = setHasAcl(sess, dash)
+		if err != nil {
+			return err
+		}
+
 		parentVersion := dash.Version
 		affectedRows := int64(0)
 
@@ -80,9 +85,9 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
 			dash.Data.Set("version", dash.Version)
 			affectedRows, err = sess.Insert(dash)
 		} else {
-			dash.Version += 1
+			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 {
@@ -111,7 +116,7 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
 			return m.ErrDashboardNotFound
 		}
 
-		// delete existing tabs
+		// delete existing tags
 		_, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.Id)
 		if err != nil {
 			return err
@@ -126,13 +131,37 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
 				}
 			}
 		}
-
 		cmd.Result = dash
 
 		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 {
 	dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id}
 	has, err := x.Get(&dashboard)

+ 104 - 18
pkg/services/sqlstore/dashboard_test.go

@@ -11,24 +11,6 @@ import (
 	"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) {
 
 	Convey("Testing DB", t, func() {
@@ -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 {
 	setting.AutoAssignOrg = true
 	setting.AutoAssignOrgRole = role
@@ -424,3 +496,17 @@ func removeAcl(aclId int64) {
 	err := RemoveDashboardAcl(&m.RemoveDashboardAclCommand{AclId: aclId, OrgId: 1})
 	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
+}