Browse Source

dashfolders: show folders use can save to in picker

Instead of returning all folders a user has some sort of access to,
this change creates a new end point that returns folders the user
has write access to. This new endpoint is used in the folder picker
Daniel Lee 8 years ago
parent
commit
94a54248c1

+ 2 - 0
pkg/api/api.go

@@ -252,6 +252,8 @@ 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))

+ 16 - 0
pkg/api/dashboard.go

@@ -438,3 +438,19 @@ 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)
+}

+ 12 - 0
pkg/models/dashboards.go

@@ -209,3 +209,15 @@ type GetDashboardSlugByIdQuery struct {
 	Id     int64
 	Result string
 }
+
+type GetFoldersForSignedInUserQuery struct {
+	OrgId        int64
+	SignedInUser *SignedInUser
+	Title        string
+	Result       []*DashboardFolder
+}
+
+type DashboardFolder struct {
+	Id    int64  `json:"id"`
+	Title string `json:"title"`
+}

+ 46 - 0
pkg/services/sqlstore/dashboard.go

@@ -18,6 +18,7 @@ func init() {
 	bus.AddHandler("sql", GetDashboardTags)
 	bus.AddHandler("sql", GetDashboardSlugById)
 	bus.AddHandler("sql", GetDashboardsByPluginId)
+	bus.AddHandler("sql", GetFoldersForSignedInUser)
 }
 
 func SaveDashboard(cmd *m.SaveDashboardCommand) error {
@@ -291,6 +292,51 @@ 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 = ?
+		ORDER BY d.title ASC`
+
+		err = x.Sql(sql, dialect.BooleanStr(true)).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 = ?`
+		params = append(params, query.SignedInUser.UserId)
+		params = append(params, query.SignedInUser.UserId)
+
+		sql += `WHERE
+			d.org_id = ? AND
+			d.is_folder = 1 AND
+			(
+				(d.has_acl = 1 AND da.permission > 1 AND (da.user_id = ? OR ugm.user_id = ? OR ou.id IS NOT NULL))
+				OR (d.has_acl = 0 AND ouRole.id IS NOT NULL)
+			)`
+		params = append(params, query.OrgId)
+		params = append(params, query.SignedInUser.UserId)
+		params = append(params, query.SignedInUser.UserId)
+
+		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}

+ 76 - 0
pkg/services/sqlstore/dashboard_test.go

@@ -459,6 +459,82 @@ func TestDashboardDataAccess(t *testing.T) {
 			})
 		})
 
+		Convey("Given two dashboard folders", func() {
+
+			folder1 := insertTestDashboard("1 test dash folder", 1, 0, true, "prod")
+			folder2 := insertTestDashboard("2 test dash folder", 1, 0, true, "prod")
+
+			adminUser := createUser("admin", "Admin", true)
+			editorUser := createUser("editor", "Editor", false)
+			viewerUser := createUser("viewer", "Viewer", false)
+
+			Convey("Admin users", func() {
+				Convey("Should have write access to all dashboard folders", func() {
+					query := m.GetFoldersForSignedInUserQuery{
+						OrgId:        1,
+						SignedInUser: &m.SignedInUser{UserId: adminUser.Id, OrgRole: m.ROLE_ADMIN},
+					}
+
+					err := GetFoldersForSignedInUser(&query)
+					So(err, ShouldBeNil)
+
+					So(len(query.Result), ShouldEqual, 2)
+					So(query.Result[0].Id, ShouldEqual, folder1.Id)
+					So(query.Result[1].Id, ShouldEqual, folder2.Id)
+				})
+			})
+
+			Convey("Editor users", func() {
+				query := m.GetFoldersForSignedInUserQuery{
+					OrgId:        1,
+					SignedInUser: &m.SignedInUser{UserId: editorUser.Id, OrgRole: m.ROLE_EDITOR},
+				}
+
+				Convey("Should have write access to all dashboard folders with default ACL", func() {
+					err := GetFoldersForSignedInUser(&query)
+					So(err, ShouldBeNil)
+
+					So(len(query.Result), ShouldEqual, 2)
+					So(query.Result[0].Id, ShouldEqual, folder1.Id)
+					So(query.Result[1].Id, ShouldEqual, folder2.Id)
+				})
+
+				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)
+					So(err, ShouldBeNil)
+
+					So(len(query.Result), ShouldEqual, 1)
+					So(query.Result[0].Id, ShouldEqual, folder2.Id)
+				})
+			})
+
+			Convey("Viewer users", func() {
+				query := m.GetFoldersForSignedInUserQuery{
+					OrgId:        1,
+					SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgRole: m.ROLE_VIEWER},
+				}
+
+				Convey("Should have no write access to any dashboard folders with default ACL", func() {
+					err := GetFoldersForSignedInUser(&query)
+					So(err, ShouldBeNil)
+
+					So(len(query.Result), ShouldEqual, 0)
+				})
+
+				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)
+					So(err, ShouldBeNil)
+
+					So(len(query.Result), ShouldEqual, 1)
+					So(query.Result[0].Id, ShouldEqual, folder1.Id)
+				})
+			})
+		})
+
 		Convey("Given a plugin with imported dashboards", func() {
 			pluginId := "test-app"
 

+ 1 - 6
public/app/features/dashboard/folder_picker/folder_picker.ts

@@ -30,12 +30,7 @@ export class FolderPickerCtrl {
   }
 
   getOptions(query) {
-    var params = {
-      query: query,
-      type: 'dash-folder',
-    };
-
-    return this.backendSrv.search(params).then(result => {
+    return this.backendSrv.get('api/dashboards/folders', { query: query }).then(result => {
       if (
         query === '' ||
         query.toLowerCase() === 'r' ||