From 892bdecb1969aa8a86dde5ecbe1dd569c19bfe57 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Tue, 20 Feb 2018 15:25:16 +0100 Subject: [PATCH] folders: folder permission api routes --- pkg/api/api.go | 14 ++++-- pkg/api/folder_acl.go | 98 +++++++++++++++++++++++++++++++++++++ pkg/models/dashboard_acl.go | 5 +- 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 pkg/api/folder_acl.go diff --git a/pkg/api/api.go b/pkg/api/api.go index 77143aed942..24cf2832af0 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -249,11 +249,19 @@ func (hs *HttpServer) registerRoutes() { // Folders apiRoute.Group("/folders", func(folderRoute RouteRegister) { folderRoute.Get("/", wrap(GetFolders)) - folderRoute.Get("/:uid", wrap(GetFolderByUid)) folderRoute.Get("/id/:id", wrap(GetFolderById)) folderRoute.Post("/", bind(m.CreateFolderCommand{}), wrap(CreateFolder)) - folderRoute.Put("/:uid", bind(m.UpdateFolderCommand{}), wrap(UpdateFolder)) - folderRoute.Delete("/:uid", wrap(DeleteFolder)) + + folderRoute.Group("/:uid", func(folderUidRoute RouteRegister) { + folderUidRoute.Get("/", wrap(GetFolderByUid)) + folderUidRoute.Put("/", bind(m.UpdateFolderCommand{}), wrap(UpdateFolder)) + folderUidRoute.Delete("/", wrap(DeleteFolder)) + + folderUidRoute.Group("/permissions", func(folderAclRoute RouteRegister) { + folderAclRoute.Get("/", wrap(GetFolderPermissionList)) + folderAclRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), wrap(UpdateFolderPermissions)) + }) + }) }) // Dashboard diff --git a/pkg/api/folder_acl.go b/pkg/api/folder_acl.go new file mode 100644 index 00000000000..5d2c28fe769 --- /dev/null +++ b/pkg/api/folder_acl.go @@ -0,0 +1,98 @@ +package api + +import ( + "time" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/guardian" +) + +func GetFolderPermissionList(c *middleware.Context) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + folder, err := s.GetFolderByUid(c.Params(":uid")) + + if err != nil { + return toFolderError(err) + } + + guardian := guardian.New(folder.Id, c.OrgId, c.SignedInUser) + + if canAdmin, err := guardian.CanAdmin(); err != nil || !canAdmin { + return toFolderError(m.ErrFolderAccessDenied) + } + + acl, err := guardian.GetAcl() + if err != nil { + return ApiError(500, "Failed to get folder permissions", err) + } + + for _, perm := range acl { + perm.FolderId = folder.Id + perm.DashboardId = 0 + + if perm.Slug != "" { + perm.Url = m.GetDashboardFolderUrl(perm.IsFolder, perm.Uid, perm.Slug) + } + } + + return Json(200, acl) +} + +func UpdateFolderPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardAclCommand) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + folder, err := s.GetFolderByUid(c.Params(":uid")) + + if err != nil { + return toFolderError(err) + } + + guardian := guardian.New(folder.Id, c.OrgId, c.SignedInUser) + if canAdmin, err := guardian.CanAdmin(); err != nil || !canAdmin { + return toFolderError(err) + } + + cmd := m.UpdateDashboardAclCommand{} + cmd.DashboardId = folder.Id + + for _, item := range apiCmd.Items { + cmd.Items = append(cmd.Items, &m.DashboardAcl{ + OrgId: c.OrgId, + DashboardId: folder.Id, + UserId: item.UserId, + TeamId: item.TeamId, + Role: item.Role, + Permission: item.Permission, + Created: time.Now(), + Updated: time.Now(), + }) + } + + if okToUpdate, err := guardian.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, cmd.Items); err != nil || !okToUpdate { + if err != nil { + return ApiError(500, "Error while checking folder permissions", err) + } + + return ApiError(403, "Cannot remove own admin permission for a folder", nil) + } + + if err := bus.Dispatch(&cmd); err != nil { + if err == m.ErrDashboardAclInfoMissing { + err = m.ErrFolderAclInfoMissing + } + if err == m.ErrDashboardPermissionDashboardEmpty { + err = m.ErrFolderPermissionFolderEmpty + } + + if err == m.ErrFolderAclInfoMissing || err == m.ErrFolderPermissionFolderEmpty { + return ApiError(409, err.Error(), err) + } + + return ApiError(500, "Failed to create permission", err) + } + + return ApiSuccess("Folder acl updated") +} diff --git a/pkg/models/dashboard_acl.go b/pkg/models/dashboard_acl.go index 202b519207d..1fbd2b451b9 100644 --- a/pkg/models/dashboard_acl.go +++ b/pkg/models/dashboard_acl.go @@ -26,6 +26,8 @@ func (p PermissionType) String() string { var ( ErrDashboardAclInfoMissing = errors.New("User id and team id cannot both be empty for a dashboard permission.") ErrDashboardPermissionDashboardEmpty = errors.New("Dashboard Id must be greater than zero for a dashboard permission.") + ErrFolderAclInfoMissing = errors.New("User id and team id cannot both be empty for a folder permission.") + ErrFolderPermissionFolderEmpty = errors.New("Folder Id must be greater than zero for a folder permission.") ) // Dashboard ACL model @@ -45,7 +47,8 @@ type DashboardAcl struct { type DashboardAclInfoDTO struct { OrgId int64 `json:"-"` - DashboardId int64 `json:"dashboardId"` + DashboardId int64 `json:"dashboardId,omitempty"` + FolderId int64 `json:"folderId,omitempty"` Created time.Time `json:"created"` Updated time.Time `json:"updated"`