mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #11034 from grafana/10701_permissions
Only allow override permissions that is higher
This commit is contained in:
commit
c298c7f3c9
@ -18,13 +18,13 @@ func GetDashboardPermissionList(c *middleware.Context) Response {
|
|||||||
return rsp
|
return rsp
|
||||||
}
|
}
|
||||||
|
|
||||||
guardian := guardian.New(dashId, c.OrgId, c.SignedInUser)
|
g := guardian.New(dashId, c.OrgId, c.SignedInUser)
|
||||||
|
|
||||||
if canAdmin, err := guardian.CanAdmin(); err != nil || !canAdmin {
|
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
|
||||||
return dashboardGuardianResponse(err)
|
return dashboardGuardianResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
acl, err := guardian.GetAcl()
|
acl, err := g.GetAcl()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ApiError(500, "Failed to get dashboard permissions", err)
|
return ApiError(500, "Failed to get dashboard permissions", err)
|
||||||
}
|
}
|
||||||
@ -46,8 +46,8 @@ func UpdateDashboardPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboa
|
|||||||
return rsp
|
return rsp
|
||||||
}
|
}
|
||||||
|
|
||||||
guardian := guardian.New(dashId, c.OrgId, c.SignedInUser)
|
g := guardian.New(dashId, c.OrgId, c.SignedInUser)
|
||||||
if canAdmin, err := guardian.CanAdmin(); err != nil || !canAdmin {
|
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
|
||||||
return dashboardGuardianResponse(err)
|
return dashboardGuardianResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,8 +67,13 @@ func UpdateDashboardPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboa
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if okToUpdate, err := guardian.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, cmd.Items); err != nil || !okToUpdate {
|
if okToUpdate, err := g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, cmd.Items); err != nil || !okToUpdate {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == guardian.ErrGuardianPermissionExists ||
|
||||||
|
err == guardian.ErrGuardianOverride {
|
||||||
|
return ApiError(400, err.Error(), err)
|
||||||
|
}
|
||||||
|
|
||||||
return ApiError(500, "Error while checking dashboard permissions", err)
|
return ApiError(500, "Error while checking dashboard permissions", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,183 +8,180 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
||||||
Convey("Given a dashboard with permissions", t, func() {
|
Convey("Dashboard permissions test", t, func() {
|
||||||
mockResult := []*m.DashboardAclInfoDTO{
|
Convey("Given dashboard not exists", func() {
|
||||||
{OrgId: 1, DashboardId: 1, UserId: 2, Permission: m.PERMISSION_VIEW},
|
bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
|
||||||
{OrgId: 1, DashboardId: 1, UserId: 3, Permission: m.PERMISSION_EDIT},
|
return m.ErrDashboardNotFound
|
||||||
{OrgId: 1, DashboardId: 1, UserId: 4, Permission: m.PERMISSION_ADMIN},
|
|
||||||
{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW},
|
|
||||||
{OrgId: 1, DashboardId: 1, TeamId: 2, Permission: m.PERMISSION_ADMIN},
|
|
||||||
}
|
|
||||||
dtoRes := transformDashboardAclsToDTOs(mockResult)
|
|
||||||
|
|
||||||
getDashboardQueryResult := m.NewDashboard("Dash")
|
|
||||||
var getDashboardNotFoundError error
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
|
|
||||||
query.Result = getDashboardQueryResult
|
|
||||||
return getDashboardNotFoundError
|
|
||||||
})
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
|
||||||
query.Result = dtoRes
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
|
||||||
query.Result = mockResult
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
teamResp := []*m.Team{}
|
|
||||||
bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
|
|
||||||
query.Result = teamResp
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// This tests four scenarios:
|
|
||||||
// 1. user is an org admin
|
|
||||||
// 2. user is an org editor AND has been granted admin permission for the dashboard
|
|
||||||
// 3. user is an org viewer AND has been granted edit permission for the dashboard
|
|
||||||
// 4. user is an org editor AND has no permissions for the dashboard
|
|
||||||
|
|
||||||
Convey("When user is org admin", func() {
|
|
||||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:dashboardsId/permissions", m.ROLE_ADMIN, func(sc *scenarioContext) {
|
|
||||||
Convey("Should be able to access ACL", func() {
|
|
||||||
sc.handlerFunc = GetDashboardPermissionList
|
|
||||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
|
||||||
|
|
||||||
So(sc.resp.Code, ShouldEqual, 200)
|
|
||||||
|
|
||||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(len(respJSON.MustArray()), ShouldEqual, 5)
|
|
||||||
So(respJSON.GetIndex(0).Get("userId").MustInt(), ShouldEqual, 2)
|
|
||||||
So(respJSON.GetIndex(0).Get("permission").MustInt(), ShouldEqual, m.PERMISSION_VIEW)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/permissions", "/api/dashboards/id/:dashboardId/permissions", m.ROLE_ADMIN, func(sc *scenarioContext) {
|
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||||
getDashboardNotFoundError = m.ErrDashboardNotFound
|
callGetDashboardPermissions(sc)
|
||||||
sc.handlerFunc = GetDashboardPermissionList
|
So(sc.resp.Code, ShouldEqual, 404)
|
||||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
|
||||||
|
|
||||||
Convey("Should not be able to access ACL", func() {
|
|
||||||
So(sc.resp.Code, ShouldEqual, 404)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Should not be able to update permissions for non-existing dashboard", func() {
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
cmd := dtos.UpdateDashboardAclCommand{
|
Items: []dtos.DashboardAclUpdateItem{
|
||||||
Items: []dtos.DashboardAclUpdateItem{
|
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
||||||
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
|
||||||
postAclScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:dashboardId/permissions", m.ROLE_ADMIN, cmd, func(sc *scenarioContext) {
|
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||||
getDashboardNotFoundError = m.ErrDashboardNotFound
|
callUpdateDashboardPermissions(sc)
|
||||||
CallPostAcl(sc)
|
So(sc.resp.Code, ShouldEqual, 404)
|
||||||
So(sc.resp.Code, ShouldEqual, 404)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("When user is org editor and has admin permission in the ACL", func() {
|
Convey("Given user has no admin permissions", func() {
|
||||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:dashboardId/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
origNewGuardian := guardian.New
|
||||||
mockResult = append(mockResult, &m.DashboardAclInfoDTO{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN})
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
|
||||||
|
|
||||||
Convey("Should be able to access ACL", func() {
|
getDashboardQueryResult := m.NewDashboard("Dash")
|
||||||
sc.handlerFunc = GetDashboardPermissionList
|
bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
|
||||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
query.Result = getDashboardQueryResult
|
||||||
|
return nil
|
||||||
So(sc.resp.Code, ShouldEqual, 200)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Should not be able to downgrade their own Admin permission", func() {
|
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||||
cmd := dtos.UpdateDashboardAclCommand{
|
callGetDashboardPermissions(sc)
|
||||||
Items: []dtos.DashboardAclUpdateItem{
|
So(sc.resp.Code, ShouldEqual, 403)
|
||||||
{UserId: TestUserID, Permission: m.PERMISSION_EDIT},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
postAclScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:dashboardId/permissions", m.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
|
|
||||||
mockResult = append(mockResult, &m.DashboardAclInfoDTO{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN})
|
|
||||||
|
|
||||||
CallPostAcl(sc)
|
|
||||||
So(sc.resp.Code, ShouldEqual, 403)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Should be able to update permissions", func() {
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
cmd := dtos.UpdateDashboardAclCommand{
|
Items: []dtos.DashboardAclUpdateItem{
|
||||||
Items: []dtos.DashboardAclUpdateItem{
|
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
||||||
{UserId: TestUserID, Permission: m.PERMISSION_ADMIN},
|
},
|
||||||
{UserId: 2, Permission: m.PERMISSION_EDIT},
|
}
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
postAclScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:dashboardId/permissions", m.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
|
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||||
mockResult = append(mockResult, &m.DashboardAclInfoDTO{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN})
|
callUpdateDashboardPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 403)
|
||||||
CallPostAcl(sc)
|
|
||||||
So(sc.resp.Code, ShouldEqual, 200)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
Reset(func() {
|
||||||
|
guardian.New = origNewGuardian
|
||||||
Convey("When user is org viewer and has edit permission in the ACL", func() {
|
|
||||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:dashboardId/permissions", m.ROLE_VIEWER, func(sc *scenarioContext) {
|
|
||||||
mockResult = append(mockResult, &m.DashboardAclInfoDTO{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_EDIT})
|
|
||||||
|
|
||||||
// Getting the permissions is an Admin permission
|
|
||||||
Convey("Should not be able to get list of permissions from ACL", func() {
|
|
||||||
sc.handlerFunc = GetDashboardPermissionList
|
|
||||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
|
||||||
|
|
||||||
So(sc.resp.Code, ShouldEqual, 403)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("When user is org editor and not in the ACL", func() {
|
Convey("Given user has admin permissions and permissions to update", func() {
|
||||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:dashboardsId/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
origNewGuardian := guardian.New
|
||||||
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||||
|
CanAdminValue: true,
|
||||||
|
CheckPermissionBeforeUpdateValue: true,
|
||||||
|
GetAclValue: []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 2, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 3, Permission: m.PERMISSION_EDIT},
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 4, Permission: m.PERMISSION_ADMIN},
|
||||||
|
{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, TeamId: 2, Permission: m.PERMISSION_ADMIN},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
Convey("Should not be able to access ACL", func() {
|
getDashboardQueryResult := m.NewDashboard("Dash")
|
||||||
sc.handlerFunc = GetDashboardPermissionList
|
bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
|
||||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
query.Result = getDashboardQueryResult
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
So(sc.resp.Code, ShouldEqual, 403)
|
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", m.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||||
})
|
callGetDashboardPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 200)
|
||||||
|
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(len(respJSON.MustArray()), ShouldEqual, 5)
|
||||||
|
So(respJSON.GetIndex(0).Get("userId").MustInt(), ShouldEqual, 2)
|
||||||
|
So(respJSON.GetIndex(0).Get("permission").MustInt(), ShouldEqual, m.PERMISSION_VIEW)
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
|
Items: []dtos.DashboardAclUpdateItem{
|
||||||
|
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||||
|
callUpdateDashboardPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 200)
|
||||||
|
})
|
||||||
|
|
||||||
|
Reset(func() {
|
||||||
|
guardian.New = origNewGuardian
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update permissions with duplicate permissions", func() {
|
||||||
|
origNewGuardian := guardian.New
|
||||||
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||||
|
CanAdminValue: true,
|
||||||
|
CheckPermissionBeforeUpdateValue: false,
|
||||||
|
CheckPermissionBeforeUpdateError: guardian.ErrGuardianPermissionExists,
|
||||||
|
})
|
||||||
|
|
||||||
|
getDashboardQueryResult := m.NewDashboard("Dash")
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
|
||||||
|
query.Result = getDashboardQueryResult
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
|
Items: []dtos.DashboardAclUpdateItem{
|
||||||
|
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||||
|
callUpdateDashboardPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 400)
|
||||||
|
})
|
||||||
|
|
||||||
|
Reset(func() {
|
||||||
|
guardian.New = origNewGuardian
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to override inherited permissions with lower presedence", func() {
|
||||||
|
origNewGuardian := guardian.New
|
||||||
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||||
|
CanAdminValue: true,
|
||||||
|
CheckPermissionBeforeUpdateValue: false,
|
||||||
|
CheckPermissionBeforeUpdateError: guardian.ErrGuardianOverride},
|
||||||
|
)
|
||||||
|
|
||||||
|
getDashboardQueryResult := m.NewDashboard("Dash")
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
|
||||||
|
query.Result = getDashboardQueryResult
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
|
Items: []dtos.DashboardAclUpdateItem{
|
||||||
|
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||||
|
callUpdateDashboardPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 400)
|
||||||
|
})
|
||||||
|
|
||||||
|
Reset(func() {
|
||||||
|
guardian.New = origNewGuardian
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func transformDashboardAclsToDTOs(acls []*m.DashboardAclInfoDTO) []*m.DashboardAclInfoDTO {
|
func callGetDashboardPermissions(sc *scenarioContext) {
|
||||||
dtos := make([]*m.DashboardAclInfoDTO, 0)
|
sc.handlerFunc = GetDashboardPermissionList
|
||||||
|
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||||
for _, acl := range acls {
|
|
||||||
dto := &m.DashboardAclInfoDTO{
|
|
||||||
OrgId: acl.OrgId,
|
|
||||||
DashboardId: acl.DashboardId,
|
|
||||||
Permission: acl.Permission,
|
|
||||||
UserId: acl.UserId,
|
|
||||||
TeamId: acl.TeamId,
|
|
||||||
}
|
|
||||||
dtos = append(dtos, dto)
|
|
||||||
}
|
|
||||||
|
|
||||||
return dtos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CallPostAcl(sc *scenarioContext) {
|
func callUpdateDashboardPermissions(sc *scenarioContext) {
|
||||||
bus.AddHandler("test", func(cmd *m.UpdateDashboardAclCommand) error {
|
bus.AddHandler("test", func(cmd *m.UpdateDashboardAclCommand) error {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -192,7 +189,7 @@ func CallPostAcl(sc *scenarioContext) {
|
|||||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
func postAclScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.UpdateDashboardAclCommand, fn scenarioFunc) {
|
func updateDashboardPermissionScenario(desc string, url string, routePattern string, cmd dtos.UpdateDashboardAclCommand, fn scenarioFunc) {
|
||||||
Convey(desc+" "+url, func() {
|
Convey(desc+" "+url, func() {
|
||||||
defer bus.ClearBusHandlers()
|
defer bus.ClearBusHandlers()
|
||||||
|
|
||||||
@ -200,9 +197,8 @@ func postAclScenario(desc string, url string, routePattern string, role m.RoleTy
|
|||||||
|
|
||||||
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
|
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
|
||||||
sc.context = c
|
sc.context = c
|
||||||
sc.context.UserId = TestUserID
|
|
||||||
sc.context.OrgId = TestOrgID
|
sc.context.OrgId = TestOrgID
|
||||||
sc.context.OrgRole = role
|
sc.context.UserId = TestUserID
|
||||||
|
|
||||||
return UpdateDashboardPermissions(c, cmd)
|
return UpdateDashboardPermissions(c, cmd)
|
||||||
})
|
})
|
||||||
|
@ -19,13 +19,13 @@ func GetFolderPermissionList(c *middleware.Context) Response {
|
|||||||
return toFolderError(err)
|
return toFolderError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
guardian := guardian.New(folder.Id, c.OrgId, c.SignedInUser)
|
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser)
|
||||||
|
|
||||||
if canAdmin, err := guardian.CanAdmin(); err != nil || !canAdmin {
|
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
|
||||||
return toFolderError(m.ErrFolderAccessDenied)
|
return toFolderError(m.ErrFolderAccessDenied)
|
||||||
}
|
}
|
||||||
|
|
||||||
acl, err := guardian.GetAcl()
|
acl, err := g.GetAcl()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ApiError(500, "Failed to get folder permissions", err)
|
return ApiError(500, "Failed to get folder permissions", err)
|
||||||
}
|
}
|
||||||
@ -50,8 +50,8 @@ func UpdateFolderPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardA
|
|||||||
return toFolderError(err)
|
return toFolderError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
guardian := guardian.New(folder.Id, c.OrgId, c.SignedInUser)
|
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser)
|
||||||
canAdmin, err := guardian.CanAdmin()
|
canAdmin, err := g.CanAdmin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return toFolderError(err)
|
return toFolderError(err)
|
||||||
}
|
}
|
||||||
@ -76,8 +76,13 @@ func UpdateFolderPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardA
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if okToUpdate, err := guardian.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, cmd.Items); err != nil || !okToUpdate {
|
if okToUpdate, err := g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, cmd.Items); err != nil || !okToUpdate {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == guardian.ErrGuardianPermissionExists ||
|
||||||
|
err == guardian.ErrGuardianOverride {
|
||||||
|
return ApiError(400, err.Error(), err)
|
||||||
|
}
|
||||||
|
|
||||||
return ApiError(500, "Error while checking folder permissions", err)
|
return ApiError(500, "Error while checking folder permissions", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/dtos"
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
@ -15,6 +16,35 @@ import (
|
|||||||
|
|
||||||
func TestFolderPermissionApiEndpoint(t *testing.T) {
|
func TestFolderPermissionApiEndpoint(t *testing.T) {
|
||||||
Convey("Folder permissions test", t, func() {
|
Convey("Folder permissions test", t, func() {
|
||||||
|
Convey("Given folder not exists", func() {
|
||||||
|
mock := &fakeFolderService{
|
||||||
|
GetFolderByUidError: m.ErrFolderNotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
origNewFolderService := dashboards.NewFolderService
|
||||||
|
mockFolderService(mock)
|
||||||
|
|
||||||
|
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||||
|
callGetFolderPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 404)
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
|
Items: []dtos.DashboardAclUpdateItem{
|
||||||
|
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||||
|
callUpdateFolderPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 404)
|
||||||
|
})
|
||||||
|
|
||||||
|
Reset(func() {
|
||||||
|
dashboards.NewFolderService = origNewFolderService
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Convey("Given user has no admin permissions", func() {
|
Convey("Given user has no admin permissions", func() {
|
||||||
origNewGuardian := guardian.New
|
origNewGuardian := guardian.New
|
||||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
|
||||||
@ -54,7 +84,17 @@ func TestFolderPermissionApiEndpoint(t *testing.T) {
|
|||||||
|
|
||||||
Convey("Given user has admin permissions and permissions to update", func() {
|
Convey("Given user has admin permissions and permissions to update", func() {
|
||||||
origNewGuardian := guardian.New
|
origNewGuardian := guardian.New
|
||||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: true, CheckPermissionBeforeUpdateValue: true})
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||||
|
CanAdminValue: true,
|
||||||
|
CheckPermissionBeforeUpdateValue: true,
|
||||||
|
GetAclValue: []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 2, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 3, Permission: m.PERMISSION_EDIT},
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 4, Permission: m.PERMISSION_ADMIN},
|
||||||
|
{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, TeamId: 2, Permission: m.PERMISSION_ADMIN},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
mock := &fakeFolderService{
|
mock := &fakeFolderService{
|
||||||
GetFolderByUidResult: &m.Folder{
|
GetFolderByUidResult: &m.Folder{
|
||||||
@ -70,6 +110,11 @@ func TestFolderPermissionApiEndpoint(t *testing.T) {
|
|||||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", m.ROLE_ADMIN, func(sc *scenarioContext) {
|
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", m.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||||
callGetFolderPermissions(sc)
|
callGetFolderPermissions(sc)
|
||||||
So(sc.resp.Code, ShouldEqual, 200)
|
So(sc.resp.Code, ShouldEqual, 200)
|
||||||
|
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(len(respJSON.MustArray()), ShouldEqual, 5)
|
||||||
|
So(respJSON.GetIndex(0).Get("userId").MustInt(), ShouldEqual, 2)
|
||||||
|
So(respJSON.GetIndex(0).Get("permission").MustInt(), ShouldEqual, m.PERMISSION_VIEW)
|
||||||
})
|
})
|
||||||
|
|
||||||
cmd := dtos.UpdateDashboardAclCommand{
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
@ -88,6 +133,78 @@ func TestFolderPermissionApiEndpoint(t *testing.T) {
|
|||||||
dashboards.NewFolderService = origNewFolderService
|
dashboards.NewFolderService = origNewFolderService
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update permissions with duplicate permissions", func() {
|
||||||
|
origNewGuardian := guardian.New
|
||||||
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||||
|
CanAdminValue: true,
|
||||||
|
CheckPermissionBeforeUpdateValue: false,
|
||||||
|
CheckPermissionBeforeUpdateError: guardian.ErrGuardianPermissionExists,
|
||||||
|
})
|
||||||
|
|
||||||
|
mock := &fakeFolderService{
|
||||||
|
GetFolderByUidResult: &m.Folder{
|
||||||
|
Id: 1,
|
||||||
|
Uid: "uid",
|
||||||
|
Title: "Folder",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
origNewFolderService := dashboards.NewFolderService
|
||||||
|
mockFolderService(mock)
|
||||||
|
|
||||||
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
|
Items: []dtos.DashboardAclUpdateItem{
|
||||||
|
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||||
|
callUpdateFolderPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 400)
|
||||||
|
})
|
||||||
|
|
||||||
|
Reset(func() {
|
||||||
|
guardian.New = origNewGuardian
|
||||||
|
dashboards.NewFolderService = origNewFolderService
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to override inherited permissions with lower presedence", func() {
|
||||||
|
origNewGuardian := guardian.New
|
||||||
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||||
|
CanAdminValue: true,
|
||||||
|
CheckPermissionBeforeUpdateValue: false,
|
||||||
|
CheckPermissionBeforeUpdateError: guardian.ErrGuardianOverride},
|
||||||
|
)
|
||||||
|
|
||||||
|
mock := &fakeFolderService{
|
||||||
|
GetFolderByUidResult: &m.Folder{
|
||||||
|
Id: 1,
|
||||||
|
Uid: "uid",
|
||||||
|
Title: "Folder",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
origNewFolderService := dashboards.NewFolderService
|
||||||
|
mockFolderService(mock)
|
||||||
|
|
||||||
|
cmd := dtos.UpdateDashboardAclCommand{
|
||||||
|
Items: []dtos.DashboardAclUpdateItem{
|
||||||
|
{UserId: 1000, Permission: m.PERMISSION_ADMIN},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||||
|
callUpdateFolderPermissions(sc)
|
||||||
|
So(sc.resp.Code, ShouldEqual, 400)
|
||||||
|
})
|
||||||
|
|
||||||
|
Reset(func() {
|
||||||
|
guardian.New = origNewGuardian
|
||||||
|
dashboards.NewFolderService = origNewFolderService
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,27 @@ type DashboardAclInfoDTO struct {
|
|||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dto *DashboardAclInfoDTO) hasSameRoleAs(other *DashboardAclInfoDTO) bool {
|
||||||
|
if dto.Role == nil || other.Role == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return dto.UserId <= 0 && dto.TeamId <= 0 && dto.UserId == other.UserId && dto.TeamId == other.TeamId && *dto.Role == *other.Role
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dto *DashboardAclInfoDTO) hasSameUserAs(other *DashboardAclInfoDTO) bool {
|
||||||
|
return dto.UserId > 0 && dto.UserId == other.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dto *DashboardAclInfoDTO) hasSameTeamAs(other *DashboardAclInfoDTO) bool {
|
||||||
|
return dto.TeamId > 0 && dto.TeamId == other.TeamId
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDuplicateOf returns true if other item has same role, same user or same team
|
||||||
|
func (dto *DashboardAclInfoDTO) IsDuplicateOf(other *DashboardAclInfoDTO) bool {
|
||||||
|
return dto.hasSameRoleAs(other) || dto.hasSameUserAs(other) || dto.hasSameTeamAs(other)
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// COMMANDS
|
// COMMANDS
|
||||||
//
|
//
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
package guardian
|
package guardian
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrGuardianPermissionExists = errors.New("Permission already exists")
|
||||||
|
ErrGuardianOverride = errors.New("You can only override a permission to be higher")
|
||||||
|
)
|
||||||
|
|
||||||
// DashboardGuardian to be used for guard against operations without access on dashboard and acl
|
// DashboardGuardian to be used for guard against operations without access on dashboard and acl
|
||||||
type DashboardGuardian interface {
|
type DashboardGuardian interface {
|
||||||
CanSave() (bool, error)
|
CanSave() (bool, error)
|
||||||
@ -119,14 +126,51 @@ func (g *dashboardGuardianImpl) checkAcl(permission m.PermissionType, acl []*m.D
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *dashboardGuardianImpl) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
|
func (g *dashboardGuardianImpl) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
|
||||||
if g.user.OrgRole == m.ROLE_ADMIN {
|
acl := []*m.DashboardAclInfoDTO{}
|
||||||
return true, nil
|
adminRole := m.ROLE_ADMIN
|
||||||
|
everyoneWithAdminRole := &m.DashboardAclInfoDTO{DashboardId: g.dashId, UserId: 0, TeamId: 0, Role: &adminRole, Permission: m.PERMISSION_ADMIN}
|
||||||
|
|
||||||
|
// validate that duplicate permissions don't exists
|
||||||
|
for _, p := range updatePermissions {
|
||||||
|
aclItem := &m.DashboardAclInfoDTO{DashboardId: p.DashboardId, UserId: p.UserId, TeamId: p.TeamId, Role: p.Role, Permission: p.Permission}
|
||||||
|
if aclItem.IsDuplicateOf(everyoneWithAdminRole) {
|
||||||
|
return false, ErrGuardianPermissionExists
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range acl {
|
||||||
|
if a.IsDuplicateOf(aclItem) {
|
||||||
|
return false, ErrGuardianPermissionExists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acl = append(acl, aclItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
acl := []*m.DashboardAclInfoDTO{}
|
existingPermissions, err := g.GetAcl()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
for _, p := range updatePermissions {
|
// validate overridden permissions to be higher
|
||||||
acl = append(acl, &m.DashboardAclInfoDTO{UserId: p.UserId, TeamId: p.TeamId, Role: p.Role, Permission: p.Permission})
|
for _, a := range acl {
|
||||||
|
for _, existingPerm := range existingPermissions {
|
||||||
|
// handle default permissions
|
||||||
|
if existingPerm.DashboardId == -1 {
|
||||||
|
existingPerm.DashboardId = g.dashId
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.DashboardId == existingPerm.DashboardId {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.IsDuplicateOf(existingPerm) && a.Permission <= existingPerm.Permission {
|
||||||
|
return false, ErrGuardianOverride
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.user.OrgRole == m.ROLE_ADMIN {
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return g.checkAcl(permission, acl)
|
return g.checkAcl(permission, acl)
|
||||||
@ -143,6 +187,13 @@ func (g *dashboardGuardianImpl) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, a := range query.Result {
|
||||||
|
// handle default permissions
|
||||||
|
if a.DashboardId == -1 {
|
||||||
|
a.DashboardId = g.dashId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g.acl = query.Result
|
g.acl = query.Result
|
||||||
return g.acl, nil
|
return g.acl, nil
|
||||||
}
|
}
|
||||||
@ -169,6 +220,8 @@ type FakeDashboardGuardian struct {
|
|||||||
CanAdminValue bool
|
CanAdminValue bool
|
||||||
HasPermissionValue bool
|
HasPermissionValue bool
|
||||||
CheckPermissionBeforeUpdateValue bool
|
CheckPermissionBeforeUpdateValue bool
|
||||||
|
CheckPermissionBeforeUpdateError error
|
||||||
|
GetAclValue []*m.DashboardAclInfoDTO
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *FakeDashboardGuardian) CanSave() (bool, error) {
|
func (g *FakeDashboardGuardian) CanSave() (bool, error) {
|
||||||
@ -192,11 +245,11 @@ func (g *FakeDashboardGuardian) HasPermission(permission m.PermissionType) (bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *FakeDashboardGuardian) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
|
func (g *FakeDashboardGuardian) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
|
||||||
return g.CheckPermissionBeforeUpdateValue, nil
|
return g.CheckPermissionBeforeUpdateValue, g.CheckPermissionBeforeUpdateError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *FakeDashboardGuardian) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
|
func (g *FakeDashboardGuardian) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
|
||||||
return nil, nil
|
return g.GetAclValue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MockDashboardGuardian(mock *FakeDashboardGuardian) {
|
func MockDashboardGuardian(mock *FakeDashboardGuardian) {
|
||||||
|
711
pkg/services/guardian/guardian_test.go
Normal file
711
pkg/services/guardian/guardian_test.go
Normal file
@ -0,0 +1,711 @@
|
|||||||
|
package guardian
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
|
||||||
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGuardian(t *testing.T) {
|
||||||
|
Convey("Guardian permission tests", t, func() {
|
||||||
|
orgRoleScenario("Given user has admin org role", m.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeTrue)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
|
||||||
|
Convey("When trying to update permissions", func() {
|
||||||
|
Convey("With duplicate user permissions should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianPermissionExists)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("With duplicate team permissions should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianPermissionExists)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("With duplicate everyone with editor role permission should return error", func() {
|
||||||
|
r := m.ROLE_EDITOR
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianPermissionExists)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("With duplicate everyone with viewer role permission should return error", func() {
|
||||||
|
r := m.ROLE_VIEWER
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianPermissionExists)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("With everyone with admin role permission should return error", func() {
|
||||||
|
r := m.ROLE_ADMIN
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianPermissionExists)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given default permissions", func() {
|
||||||
|
editor := m.ROLE_EDITOR
|
||||||
|
viewer := m.ROLE_VIEWER
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: -1, Role: &editor, Permission: m.PERMISSION_EDIT},
|
||||||
|
{OrgId: 1, DashboardId: -1, Role: &viewer, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions without everyone with role editor can edit should be allowed", func() {
|
||||||
|
r := m.ROLE_VIEWER
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions without everyone with role viewer can view should be allowed", func() {
|
||||||
|
r := m.ROLE_EDITOR
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given parent folder has user admin permission", func() {
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with admin user permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with edit user permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with view user permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given parent folder has user edit permission", func() {
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with admin user permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with edit user permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with view user permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given parent folder has user view permission", func() {
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with admin user permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with edit user permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with view user permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given parent folder has team admin permission", func() {
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with admin team permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with edit team permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with view team permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given parent folder has team edit permission", func() {
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with admin team permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with edit team permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with view team permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given parent folder has team view permission", func() {
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with admin team permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with edit team permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with view team permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given parent folder has editor role with edit permission", func() {
|
||||||
|
r := m.ROLE_EDITOR
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 2, Role: &r, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with everyone with editor role can admin permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with everyone with editor role can edit permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with everyone with editor role can view permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Given parent folder has editor role with view permission", func() {
|
||||||
|
r := m.ROLE_EDITOR
|
||||||
|
existingPermissions := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 2, Role: &r, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = existingPermissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with everyone with viewer role can admin permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with everyone with viewer role can edit permission should be allowed", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_EDIT},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update dashboard permissions with everyone with viewer role can view permission should return error", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_VIEW},
|
||||||
|
}
|
||||||
|
_, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(err, ShouldEqual, ErrGuardianOverride)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
orgRoleScenario("Given user has editor org role", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||||
|
everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeTrue)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
userWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeTrue)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
userWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
userWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
teamWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeTrue)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
teamWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
teamWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update permissions should return false", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeFalse)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
orgRoleScenario("Given user has viewer org role", m.ROLE_VIEWER, func(sc *scenarioContext) {
|
||||||
|
everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeTrue)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
userWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeTrue)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
userWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeTrue)
|
||||||
|
So(canSave, ShouldBeTrue)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
userWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) {
|
||||||
|
canAdmin, _ := sc.g.CanAdmin()
|
||||||
|
canEdit, _ := sc.g.CanEdit()
|
||||||
|
canSave, _ := sc.g.CanSave()
|
||||||
|
canView, _ := sc.g.CanView()
|
||||||
|
So(canAdmin, ShouldBeFalse)
|
||||||
|
So(canEdit, ShouldBeFalse)
|
||||||
|
So(canSave, ShouldBeFalse)
|
||||||
|
So(canView, ShouldBeTrue)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When trying to update permissions should return false", func() {
|
||||||
|
p := []*m.DashboardAcl{
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW},
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN},
|
||||||
|
}
|
||||||
|
ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p)
|
||||||
|
So(ok, ShouldBeFalse)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type scenarioContext struct {
|
||||||
|
g DashboardGuardian
|
||||||
|
}
|
||||||
|
|
||||||
|
type scenarioFunc func(c *scenarioContext)
|
||||||
|
|
||||||
|
func orgRoleScenario(desc string, role m.RoleType, fn scenarioFunc) {
|
||||||
|
user := &m.SignedInUser{
|
||||||
|
UserId: 1,
|
||||||
|
OrgId: 1,
|
||||||
|
OrgRole: role,
|
||||||
|
}
|
||||||
|
guard := New(1, 1, user)
|
||||||
|
sc := &scenarioContext{
|
||||||
|
g: guard,
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey(desc, func() {
|
||||||
|
fn(sc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func permissionScenario(desc string, sc *scenarioContext, permissions []*m.DashboardAclInfoDTO, fn scenarioFunc) {
|
||||||
|
bus.ClearBusHandlers()
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
|
||||||
|
query.Result = permissions
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
teams := []*m.Team{}
|
||||||
|
|
||||||
|
for _, p := range permissions {
|
||||||
|
if p.TeamId > 0 {
|
||||||
|
teams = append(teams, &m.Team{Id: p.TeamId})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
|
||||||
|
query.Result = teams
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey(desc, func() {
|
||||||
|
fn(sc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func userWithPermissionScenario(permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) {
|
||||||
|
p := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: 1, Permission: permission},
|
||||||
|
}
|
||||||
|
permissionScenario(fmt.Sprintf("and user has permission to %s item", permission), sc, p, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func teamWithPermissionScenario(permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) {
|
||||||
|
p := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: permission},
|
||||||
|
}
|
||||||
|
permissionScenario(fmt.Sprintf("and team has permission to %s item", permission), sc, p, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func everyoneWithRoleScenario(role m.RoleType, permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) {
|
||||||
|
p := []*m.DashboardAclInfoDTO{
|
||||||
|
{OrgId: 1, DashboardId: 1, UserId: -1, Role: &role, Permission: permission},
|
||||||
|
}
|
||||||
|
permissionScenario(fmt.Sprintf("and everyone with %s role can %s item", role, permission), sc, p, fn)
|
||||||
|
}
|
@ -17,7 +17,7 @@ describe('AddPermissions', () => {
|
|||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
backendSrv.post = jest.fn();
|
backendSrv.post = jest.fn(() => Promise.resolve({}));
|
||||||
|
|
||||||
store = RootStore.create(
|
store = RootStore.create(
|
||||||
{},
|
{},
|
||||||
|
@ -135,14 +135,6 @@ class AddPermissions extends Component<IProps, any> {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{permissions.error ? (
|
|
||||||
<div className="gf-form width-17">
|
|
||||||
<span ng-if="ctrl.error" className="text-error p-l-1">
|
|
||||||
<i className="fa fa-warning" />
|
|
||||||
{permissions.error}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { PermissionsStore, aclTypeValues } from './PermissionsStore';
|
import { PermissionsStore } from './PermissionsStore';
|
||||||
import { backendSrv } from 'test/mocks/common';
|
import { backendSrv } from 'test/mocks/common';
|
||||||
|
|
||||||
describe('PermissionsStore', () => {
|
describe('PermissionsStore', () => {
|
||||||
let store;
|
let store;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
backendSrv.get.mockReturnValue(
|
backendSrv.get.mockReturnValue(
|
||||||
Promise.resolve([
|
Promise.resolve([
|
||||||
{ id: 2, dashboardId: 1, role: 'Viewer', permission: 1, permissionName: 'View' },
|
{ id: 2, dashboardId: 1, role: 'Viewer', permission: 1, permissionName: 'View' },
|
||||||
@ -20,7 +20,7 @@ describe('PermissionsStore', () => {
|
|||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
backendSrv.post = jest.fn();
|
backendSrv.post = jest.fn(() => Promise.resolve({}));
|
||||||
|
|
||||||
store = PermissionsStore.create(
|
store = PermissionsStore.create(
|
||||||
{
|
{
|
||||||
@ -32,14 +32,14 @@ describe('PermissionsStore', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return store.load(1, false, false);
|
await store.load(1, false, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should save update on permission change', () => {
|
it('should save update on permission change', async () => {
|
||||||
expect(store.items[0].permission).toBe(1);
|
expect(store.items[0].permission).toBe(1);
|
||||||
expect(store.items[0].permissionName).toBe('View');
|
expect(store.items[0].permissionName).toBe('View');
|
||||||
|
|
||||||
store.updatePermissionOnIndex(0, 2, 'Edit');
|
await store.updatePermissionOnIndex(0, 2, 'Edit');
|
||||||
|
|
||||||
expect(store.items[0].permission).toBe(2);
|
expect(store.items[0].permission).toBe(2);
|
||||||
expect(store.items[0].permissionName).toBe('Edit');
|
expect(store.items[0].permissionName).toBe('Edit');
|
||||||
@ -47,69 +47,18 @@ describe('PermissionsStore', () => {
|
|||||||
expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/permissions');
|
expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/permissions');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should save removed permissions automatically', () => {
|
it('should save removed permissions automatically', async () => {
|
||||||
expect(store.items.length).toBe(3);
|
expect(store.items.length).toBe(3);
|
||||||
|
|
||||||
store.removeStoreItem(2);
|
await store.removeStoreItem(2);
|
||||||
|
|
||||||
expect(store.items.length).toBe(2);
|
expect(store.items.length).toBe(2);
|
||||||
expect(backendSrv.post.mock.calls.length).toBe(1);
|
expect(backendSrv.post.mock.calls.length).toBe(1);
|
||||||
expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/permissions');
|
expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/permissions');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when duplicate team permissions are added', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
const newItem = {
|
|
||||||
teamId: 10,
|
|
||||||
team: 'tester-team',
|
|
||||||
permission: 1,
|
|
||||||
dashboardId: 1,
|
|
||||||
};
|
|
||||||
store.resetNewType();
|
|
||||||
store.newItem.setTeam(newItem.teamId, newItem.team);
|
|
||||||
store.newItem.setPermission(newItem.permission);
|
|
||||||
store.addStoreItem();
|
|
||||||
|
|
||||||
store.newItem.setTeam(newItem.teamId, newItem.team);
|
|
||||||
store.newItem.setPermission(newItem.permission);
|
|
||||||
store.addStoreItem();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return a validation error', () => {
|
|
||||||
expect(store.items.length).toBe(4);
|
|
||||||
expect(store.error).toBe('This permission exists already.');
|
|
||||||
expect(backendSrv.post.mock.calls.length).toBe(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when duplicate user permissions are added', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
expect(store.items.length).toBe(3);
|
|
||||||
const newItem = {
|
|
||||||
userId: 10,
|
|
||||||
userLogin: 'tester1',
|
|
||||||
permission: 1,
|
|
||||||
dashboardId: 1,
|
|
||||||
};
|
|
||||||
store.setNewType(aclTypeValues.USER.value);
|
|
||||||
store.newItem.setUser(newItem.userId, newItem.userLogin);
|
|
||||||
store.newItem.setPermission(newItem.permission);
|
|
||||||
store.addStoreItem();
|
|
||||||
store.setNewType(aclTypeValues.USER.value);
|
|
||||||
store.newItem.setUser(newItem.userId, newItem.userLogin);
|
|
||||||
store.newItem.setPermission(newItem.permission);
|
|
||||||
store.addStoreItem();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return a validation error', () => {
|
|
||||||
expect(store.items.length).toBe(4);
|
|
||||||
expect(store.error).toBe('This permission exists already.');
|
|
||||||
expect(backendSrv.post.mock.calls.length).toBe(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when one inherited and one not inherited team permission are added', () => {
|
describe('when one inherited and one not inherited team permission are added', () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
const overridingItemForChildDashboard = {
|
const overridingItemForChildDashboard = {
|
||||||
team: 'MyTestTeam',
|
team: 'MyTestTeam',
|
||||||
dashboardId: 1,
|
dashboardId: 1,
|
||||||
@ -120,11 +69,7 @@ describe('PermissionsStore', () => {
|
|||||||
store.resetNewType();
|
store.resetNewType();
|
||||||
store.newItem.setTeam(overridingItemForChildDashboard.teamId, overridingItemForChildDashboard.team);
|
store.newItem.setTeam(overridingItemForChildDashboard.teamId, overridingItemForChildDashboard.team);
|
||||||
store.newItem.setPermission(overridingItemForChildDashboard.permission);
|
store.newItem.setPermission(overridingItemForChildDashboard.permission);
|
||||||
store.addStoreItem();
|
await store.addStoreItem();
|
||||||
});
|
|
||||||
|
|
||||||
it('should allowing overriding the inherited permission and not throw a validation error', () => {
|
|
||||||
expect(store.error).toBe(null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add new overriding permission', () => {
|
it('should add new overriding permission', () => {
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { types, getEnv, flow } from 'mobx-state-tree';
|
import { types, getEnv, flow } from 'mobx-state-tree';
|
||||||
import { PermissionsStoreItem } from './PermissionsStoreItem';
|
import { PermissionsStoreItem } from './PermissionsStoreItem';
|
||||||
|
|
||||||
const duplicateError = 'This permission exists already.';
|
|
||||||
|
|
||||||
export const permissionOptions = [
|
export const permissionOptions = [
|
||||||
{ value: 1, label: 'View', description: 'Can view dashboards.' },
|
{ value: 1, label: 'View', description: 'Can view dashboards.' },
|
||||||
{ value: 2, label: 'Edit', description: 'Can add, edit and delete dashboards.' },
|
{ value: 2, label: 'Edit', description: 'Can add, edit and delete dashboards.' },
|
||||||
@ -75,7 +73,6 @@ export const PermissionsStore = types
|
|||||||
isFolder: types.maybe(types.boolean),
|
isFolder: types.maybe(types.boolean),
|
||||||
dashboardId: types.maybe(types.number),
|
dashboardId: types.maybe(types.number),
|
||||||
items: types.optional(types.array(PermissionsStoreItem), []),
|
items: types.optional(types.array(PermissionsStoreItem), []),
|
||||||
error: types.maybe(types.string),
|
|
||||||
originalItems: types.optional(types.array(PermissionsStoreItem), []),
|
originalItems: types.optional(types.array(PermissionsStoreItem), []),
|
||||||
newType: types.optional(types.string, defaultNewType),
|
newType: types.optional(types.string, defaultNewType),
|
||||||
newItem: types.maybe(NewPermissionsItem),
|
newItem: types.maybe(NewPermissionsItem),
|
||||||
@ -88,7 +85,6 @@ export const PermissionsStore = types
|
|||||||
return isDuplicate(it, item);
|
return isDuplicate(it, item);
|
||||||
});
|
});
|
||||||
if (dupe) {
|
if (dupe) {
|
||||||
self.error = duplicateError;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,8 +92,7 @@ export const PermissionsStore = types
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
.actions(self => {
|
.actions(self => {
|
||||||
const resetNewType = () => {
|
const resetNewTypeInternal = () => {
|
||||||
self.error = null;
|
|
||||||
self.newItem = NewPermissionsItem.create();
|
self.newItem = NewPermissionsItem.create();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,11 +110,9 @@ export const PermissionsStore = types
|
|||||||
self.items = items;
|
self.items = items;
|
||||||
self.originalItems = items;
|
self.originalItems = items;
|
||||||
self.fetching = false;
|
self.fetching = false;
|
||||||
self.error = null;
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
addStoreItem: flow(function* addStoreItem() {
|
addStoreItem: flow(function* addStoreItem() {
|
||||||
self.error = null;
|
|
||||||
let item = {
|
let item = {
|
||||||
type: self.newItem.type,
|
type: self.newItem.type,
|
||||||
permission: self.newItem.permission,
|
permission: self.newItem.permission,
|
||||||
@ -147,19 +140,21 @@ export const PermissionsStore = types
|
|||||||
throw Error('Unknown type: ' + self.newItem.type);
|
throw Error('Unknown type: ' + self.newItem.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.isValid(item)) {
|
const updatedItems = self.items.peek();
|
||||||
return undefined;
|
const newItem = prepareItem(item, self.dashboardId, self.isFolder, self.isInRoot);
|
||||||
}
|
updatedItems.push(newItem);
|
||||||
|
|
||||||
self.items.push(prepareItem(item, self.dashboardId, self.isFolder, self.isInRoot));
|
try {
|
||||||
resetNewType();
|
yield updateItems(self, updatedItems);
|
||||||
return updateItems(self);
|
self.items.push(newItem);
|
||||||
|
resetNewTypeInternal();
|
||||||
|
} catch {}
|
||||||
|
yield Promise.resolve();
|
||||||
}),
|
}),
|
||||||
|
|
||||||
removeStoreItem: flow(function* removeStoreItem(idx: number) {
|
removeStoreItem: flow(function* removeStoreItem(idx: number) {
|
||||||
self.error = null;
|
|
||||||
self.items.splice(idx, 1);
|
self.items.splice(idx, 1);
|
||||||
return updateItems(self);
|
yield updateItems(self, self.items.peek());
|
||||||
}),
|
}),
|
||||||
|
|
||||||
updatePermissionOnIndex: flow(function* updatePermissionOnIndex(
|
updatePermissionOnIndex: flow(function* updatePermissionOnIndex(
|
||||||
@ -167,9 +162,8 @@ export const PermissionsStore = types
|
|||||||
permission: number,
|
permission: number,
|
||||||
permissionName: string
|
permissionName: string
|
||||||
) {
|
) {
|
||||||
self.error = null;
|
|
||||||
self.items[idx].updatePermission(permission, permissionName);
|
self.items[idx].updatePermission(permission, permissionName);
|
||||||
return updateItems(self);
|
yield updateItems(self, self.items.peek());
|
||||||
}),
|
}),
|
||||||
|
|
||||||
setNewType(newType: string) {
|
setNewType(newType: string) {
|
||||||
@ -177,7 +171,7 @@ export const PermissionsStore = types
|
|||||||
},
|
},
|
||||||
|
|
||||||
resetNewType() {
|
resetNewType() {
|
||||||
resetNewType();
|
resetNewTypeInternal();
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleAddPermissions() {
|
toggleAddPermissions() {
|
||||||
@ -190,12 +184,10 @@ export const PermissionsStore = types
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateItems = self => {
|
const updateItems = (self, items) => {
|
||||||
self.error = null;
|
|
||||||
|
|
||||||
const backendSrv = getEnv(self).backendSrv;
|
const backendSrv = getEnv(self).backendSrv;
|
||||||
const updated = [];
|
const updated = [];
|
||||||
for (let item of self.items) {
|
for (let item of items) {
|
||||||
if (item.inherited) {
|
if (item.inherited) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -208,16 +200,9 @@ const updateItems = self => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let res;
|
return backendSrv.post(`/api/dashboards/id/${self.dashboardId}/permissions`, {
|
||||||
try {
|
items: updated,
|
||||||
res = backendSrv.post(`/api/dashboards/id/${self.dashboardId}/permissions`, {
|
});
|
||||||
items: updated,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
self.error = error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const prepareServerResponse = (response, dashboardId: number, isFolder: boolean, isInRoot: boolean) => {
|
const prepareServerResponse = (response, dashboardId: number, isFolder: boolean, isInRoot: boolean) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user