Chore: Propagate context for dashboard guardian (#39201)

Require guardian.New to take context.Context as first argument. 
Migrates the GetDashboardAclInfoListQuery to be dispatched using context.

Ref #36734

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
Co-authored-by: sam boyer <sam.boyer@grafana.com>
This commit is contained in:
Marcus Efraimsson 2021-09-23 17:43:32 +02:00 committed by GitHub
parent 914ae81026
commit 518a0d0458
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 117 additions and 87 deletions

View File

@ -1,10 +1,15 @@
package api package api
import "github.com/grafana/grafana/pkg/models" import (
"context"
"github.com/grafana/grafana/pkg/dashboards"
"github.com/grafana/grafana/pkg/models"
)
// updateDashboardACL updates a dashboard's ACL items. // updateDashboardACL updates a dashboard's ACL items.
// //
// Stubbable by tests. // Stubbable by tests.
var updateDashboardACL = func(hs *HTTPServer, dashID int64, items []*models.DashboardAcl) error { var updateDashboardACL = func(ctx context.Context, s dashboards.Store, dashID int64, items []*models.DashboardAcl) error {
return hs.SQLStore.UpdateDashboardACL(dashID, items) return s.UpdateDashboardACLCtx(ctx, dashID, items)
} }

View File

@ -462,7 +462,7 @@ func PauseAlert(c *models.ReqContext, dto dtos.PauseAlertCommand) response.Respo
return response.Error(500, "Get Alert failed", err) return response.Error(500, "Get Alert failed", err)
} }
guardian := guardian.New(query.Result.DashboardId, c.OrgId, c.SignedInUser) guardian := guardian.New(c.Req.Context(), query.Result.DashboardId, c.OrgId, c.SignedInUser)
if canEdit, err := guardian.CanEdit(); err != nil || !canEdit { if canEdit, err := guardian.CanEdit(); err != nil || !canEdit {
if err != nil { if err != nil {
return response.Error(500, "Error while checking permissions for Alert", err) return response.Error(500, "Error while checking permissions for Alert", err)

View File

@ -265,7 +265,7 @@ func canSaveByDashboardID(c *models.ReqContext, dashboardID int64) (bool, error)
} }
if dashboardID != 0 { if dashboardID != 0 {
guard := guardian.New(dashboardID, c.OrgId, c.SignedInUser) guard := guardian.New(c.Req.Context(), dashboardID, c.OrgId, c.SignedInUser)
if canEdit, err := guard.CanEdit(); err != nil || !canEdit { if canEdit, err := guard.CanEdit(); err != nil || !canEdit {
return false, err return false, err
} }

View File

@ -91,7 +91,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
} }
} }
guardian := guardian.New(dash.Id, c.OrgId, c.SignedInUser) guardian := guardian.New(c.Req.Context(), dash.Id, c.OrgId, c.SignedInUser)
if canView, err := guardian.CanView(); err != nil || !canView { if canView, err := guardian.CanView(); err != nil || !canView {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
@ -238,7 +238,7 @@ func (hs *HTTPServer) deleteDashboard(c *models.ReqContext) response.Response {
return rsp return rsp
} }
guardian := guardian.New(dash.Id, c.OrgId, c.SignedInUser) guardian := guardian.New(c.Req.Context(), dash.Id, c.OrgId, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave { if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
@ -508,7 +508,7 @@ func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *models.ReqContext
func GetDashboardVersions(c *models.ReqContext) response.Response { func GetDashboardVersions(c *models.ReqContext) response.Response {
dashID := c.ParamsInt64(":dashboardId") dashID := c.ParamsInt64(":dashboardId")
guardian := guardian.New(dashID, c.OrgId, c.SignedInUser) guardian := guardian.New(c.Req.Context(), dashID, c.OrgId, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave { if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
@ -547,7 +547,7 @@ func GetDashboardVersions(c *models.ReqContext) response.Response {
func GetDashboardVersion(c *models.ReqContext) response.Response { func GetDashboardVersion(c *models.ReqContext) response.Response {
dashID := c.ParamsInt64(":dashboardId") dashID := c.ParamsInt64(":dashboardId")
guardian := guardian.New(dashID, c.OrgId, c.SignedInUser) guardian := guardian.New(c.Req.Context(), dashID, c.OrgId, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave { if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
@ -584,13 +584,13 @@ func GetDashboardVersion(c *models.ReqContext) response.Response {
// POST /api/dashboards/calculate-diff performs diffs on two dashboards // POST /api/dashboards/calculate-diff performs diffs on two dashboards
func CalculateDashboardDiff(c *models.ReqContext, apiOptions dtos.CalculateDiffOptions) response.Response { func CalculateDashboardDiff(c *models.ReqContext, apiOptions dtos.CalculateDiffOptions) response.Response {
guardianBase := guardian.New(apiOptions.Base.DashboardId, c.OrgId, c.SignedInUser) guardianBase := guardian.New(c.Req.Context(), apiOptions.Base.DashboardId, c.OrgId, c.SignedInUser)
if canSave, err := guardianBase.CanSave(); err != nil || !canSave { if canSave, err := guardianBase.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
if apiOptions.Base.DashboardId != apiOptions.New.DashboardId { if apiOptions.Base.DashboardId != apiOptions.New.DashboardId {
guardianNew := guardian.New(apiOptions.New.DashboardId, c.OrgId, c.SignedInUser) guardianNew := guardian.New(c.Req.Context(), apiOptions.New.DashboardId, c.OrgId, c.SignedInUser)
if canSave, err := guardianNew.CanSave(); err != nil || !canSave { if canSave, err := guardianNew.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
@ -633,7 +633,7 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext, apiCmd dtos.
return rsp return rsp
} }
guardian := guardian.New(dash.Id, c.OrgId, c.SignedInUser) guardian := guardian.New(c.Req.Context(), dash.Id, c.OrgId, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave { if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }

View File

@ -18,7 +18,7 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *models.ReqContext) response.
return rsp return rsp
} }
g := guardian.New(dashID, c.OrgId, c.SignedInUser) g := guardian.New(c.Req.Context(), dashID, c.OrgId, c.SignedInUser)
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin { if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
@ -62,7 +62,7 @@ func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext, apiCmd dt
return rsp return rsp
} }
g := guardian.New(dashID, c.OrgId, c.SignedInUser) g := guardian.New(c.Req.Context(), dashID, c.OrgId, c.SignedInUser)
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin { if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return dashboardGuardianResponse(err) return dashboardGuardianResponse(err)
} }
@ -99,7 +99,7 @@ func (hs *HTTPServer) UpdateDashboardPermissions(c *models.ReqContext, apiCmd dt
return response.Error(403, "Cannot remove own admin permission for a folder", nil) return response.Error(403, "Cannot remove own admin permission for a folder", nil)
} }
if err := updateDashboardACL(hs, dashID, items); err != nil { if err := updateDashboardACL(c.Req.Context(), hs.SQLStore, dashID, items); err != nil {
if errors.Is(err, models.ErrDashboardAclInfoMissing) || if errors.Is(err, models.ErrDashboardAclInfoMissing) ||
errors.Is(err, models.ErrDashboardPermissionDashboardEmpty) { errors.Is(err, models.ErrDashboardPermissionDashboardEmpty) {
return response.Error(409, err.Error(), err) return response.Error(409, err.Error(), err)

View File

@ -6,15 +6,17 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/dashboards"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestDashboardPermissionAPIEndpoint(t *testing.T) { func TestDashboardPermissionAPIEndpoint(t *testing.T) {
@ -342,7 +344,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
updateDashboardACL = origUpdateDashboardACL updateDashboardACL = origUpdateDashboardACL
}) })
var gotItems []*models.DashboardAcl var gotItems []*models.DashboardAcl
updateDashboardACL = func(hs *HTTPServer, folderID int64, items []*models.DashboardAcl) error { updateDashboardACL = func(_ context.Context, _ dashboards.Store, folderID int64, items []*models.DashboardAcl) error {
gotItems = items gotItems = items
return nil return nil
} }
@ -368,7 +370,7 @@ func callUpdateDashboardPermissions(t *testing.T, sc *scenarioContext) {
t.Cleanup(func() { t.Cleanup(func() {
updateDashboardACL = origUpdateDashboardACL updateDashboardACL = origUpdateDashboardACL
}) })
updateDashboardACL = func(hs *HTTPServer, dashID int64, items []*models.DashboardAcl) error { updateDashboardACL = func(_ context.Context, _ dashboards.Store, dashID int64, items []*models.DashboardAcl) error {
return nil return nil
} }

View File

@ -254,7 +254,7 @@ func DeleteDashboardSnapshot(c *models.ReqContext) response.Response {
dashboardID := query.Result.Dashboard.Get("id").MustInt64() dashboardID := query.Result.Dashboard.Get("id").MustInt64()
guardian := guardian.New(dashboardID, c.OrgId, c.SignedInUser) guardian := guardian.New(c.Req.Context(), dashboardID, c.OrgId, c.SignedInUser)
canEdit, err := guardian.CanEdit() canEdit, err := guardian.CanEdit()
if err != nil { if err != nil {
return response.Error(500, "Error while checking permissions for snapshot", err) return response.Error(500, "Error while checking permissions for snapshot", err)

View File

@ -44,7 +44,7 @@ func (hs *HTTPServer) GetFolderByUID(c *models.ReqContext) response.Response {
return apierrors.ToFolderErrorResponse(err) return apierrors.ToFolderErrorResponse(err)
} }
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) g := guardian.New(c.Req.Context(), folder.Id, c.OrgId, c.SignedInUser)
return response.JSON(200, toFolderDto(c.Req.Context(), g, folder)) return response.JSON(200, toFolderDto(c.Req.Context(), g, folder))
} }
@ -55,7 +55,7 @@ func (hs *HTTPServer) GetFolderByID(c *models.ReqContext) response.Response {
return apierrors.ToFolderErrorResponse(err) return apierrors.ToFolderErrorResponse(err)
} }
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) g := guardian.New(c.Req.Context(), folder.Id, c.OrgId, c.SignedInUser)
return response.JSON(200, toFolderDto(c.Req.Context(), g, folder)) return response.JSON(200, toFolderDto(c.Req.Context(), g, folder))
} }
@ -73,7 +73,7 @@ func (hs *HTTPServer) CreateFolder(c *models.ReqContext, cmd models.CreateFolder
} }
} }
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) g := guardian.New(c.Req.Context(), folder.Id, c.OrgId, c.SignedInUser)
return response.JSON(200, toFolderDto(c.Req.Context(), g, folder)) return response.JSON(200, toFolderDto(c.Req.Context(), g, folder))
} }
@ -84,7 +84,7 @@ func (hs *HTTPServer) UpdateFolder(c *models.ReqContext, cmd models.UpdateFolder
return apierrors.ToFolderErrorResponse(err) return apierrors.ToFolderErrorResponse(err)
} }
g := guardian.New(cmd.Result.Id, c.OrgId, c.SignedInUser) g := guardian.New(c.Req.Context(), cmd.Result.Id, c.OrgId, c.SignedInUser)
return response.JSON(200, toFolderDto(c.Req.Context(), g, cmd.Result)) return response.JSON(200, toFolderDto(c.Req.Context(), g, cmd.Result))
} }

View File

@ -4,6 +4,8 @@ import (
"errors" "errors"
"time" "time"
macaron "gopkg.in/macaron.v1"
"github.com/grafana/grafana/pkg/api/apierrors" "github.com/grafana/grafana/pkg/api/apierrors"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
@ -11,7 +13,6 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
macaron "gopkg.in/macaron.v1"
) )
func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) response.Response { func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) response.Response {
@ -22,7 +23,7 @@ func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) response.Res
return apierrors.ToFolderErrorResponse(err) return apierrors.ToFolderErrorResponse(err)
} }
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) g := guardian.New(c.Req.Context(), folder.Id, c.OrgId, c.SignedInUser)
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin { if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return apierrors.ToFolderErrorResponse(models.ErrFolderAccessDenied) return apierrors.ToFolderErrorResponse(models.ErrFolderAccessDenied)
@ -69,7 +70,7 @@ func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext, apiCmd dtos.
return apierrors.ToFolderErrorResponse(err) return apierrors.ToFolderErrorResponse(err)
} }
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) g := guardian.New(c.Req.Context(), folder.Id, c.OrgId, c.SignedInUser)
canAdmin, err := g.CanAdmin() canAdmin, err := g.CanAdmin()
if err != nil { if err != nil {
return apierrors.ToFolderErrorResponse(err) return apierrors.ToFolderErrorResponse(err)
@ -112,7 +113,7 @@ func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext, apiCmd dtos.
return response.Error(403, "Cannot remove own admin permission for a folder", nil) return response.Error(403, "Cannot remove own admin permission for a folder", nil)
} }
if err := updateDashboardACL(hs, folder.Id, items); err != nil { if err := updateDashboardACL(c.Req.Context(), hs.SQLStore, folder.Id, items); err != nil {
if errors.Is(err, models.ErrDashboardAclInfoMissing) { if errors.Is(err, models.ErrDashboardAclInfoMissing) {
err = models.ErrFolderAclInfoMissing err = models.ErrFolderAclInfoMissing
} }

View File

@ -1,20 +1,23 @@
package api package api
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
dashboardifaces "github.com/grafana/grafana/pkg/dashboards"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestFolderPermissionAPIEndpoint(t *testing.T) { func TestFolderPermissionAPIEndpoint(t *testing.T) {
@ -360,7 +363,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
updateDashboardACL = origUpdateDashboardACL updateDashboardACL = origUpdateDashboardACL
}) })
var gotItems []*models.DashboardAcl var gotItems []*models.DashboardAcl
updateDashboardACL = func(hs *HTTPServer, dashID int64, items []*models.DashboardAcl) error { updateDashboardACL = func(_ context.Context, _ dashboardifaces.Store, _ int64, items []*models.DashboardAcl) error {
gotItems = items gotItems = items
return nil return nil
} }
@ -385,7 +388,7 @@ func callUpdateFolderPermissions(t *testing.T, sc *scenarioContext) {
t.Cleanup(func() { t.Cleanup(func() {
updateDashboardACL = origUpdateDashboardACL updateDashboardACL = origUpdateDashboardACL
}) })
updateDashboardACL = func(hs *HTTPServer, dashID int64, items []*models.DashboardAcl) error { updateDashboardACL = func(_ context.Context, _ dashboardifaces.Store, dashID int64, items []*models.DashboardAcl) error {
return nil return nil
} }

View File

@ -1,6 +1,10 @@
package dashboards package dashboards
import "github.com/grafana/grafana/pkg/models" import (
"context"
"github.com/grafana/grafana/pkg/models"
)
// Store is a dashboard store. // Store is a dashboard store.
type Store interface { type Store interface {
@ -12,7 +16,7 @@ type Store interface {
GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error) GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error)
SaveProvisionedDashboard(cmd models.SaveDashboardCommand, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) SaveProvisionedDashboard(cmd models.SaveDashboardCommand, provisioning *models.DashboardProvisioning) (*models.Dashboard, error)
SaveDashboard(cmd models.SaveDashboardCommand) (*models.Dashboard, error) SaveDashboard(cmd models.SaveDashboardCommand) (*models.Dashboard, error)
UpdateDashboardACL(uid int64, items []*models.DashboardAcl) error UpdateDashboardACLCtx(ctx context.Context, uid int64, items []*models.DashboardAcl) error
// SaveAlerts saves dashboard alerts. // SaveAlerts saves dashboard alerts.
SaveAlerts(dashID int64, alerts []*models.Alert) error SaveAlerts(dashID int64, alerts []*models.Alert) error
} }

View File

@ -43,7 +43,7 @@ func (dr *dashboardServiceImpl) MakeUserAdmin(ctx context.Context, orgID int64,
) )
} }
if err := dr.dashboardStore.UpdateDashboardACL(dashboardID, items); err != nil { if err := dr.dashboardStore.UpdateDashboardACLCtx(ctx, dashboardID, items); err != nil {
return err return err
} }

View File

@ -124,7 +124,7 @@ func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO,
} }
if isParentFolderChanged { if isParentFolderChanged {
folderGuardian := guardian.New(dash.FolderId, dto.OrgId, dto.User) folderGuardian := guardian.New(context.TODO(), dash.FolderId, dto.OrgId, dto.User)
if canSave, err := folderGuardian.CanSave(); err != nil || !canSave { if canSave, err := folderGuardian.CanSave(); err != nil || !canSave {
if err != nil { if err != nil {
return nil, err return nil, err
@ -144,7 +144,7 @@ func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO,
} }
} }
guard := guardian.New(dash.GetDashboardIdForSavePermissionCheck(), dto.OrgId, dto.User) guard := guardian.New(context.TODO(), dash.GetDashboardIdForSavePermissionCheck(), dto.OrgId, dto.User)
if canSave, err := guard.CanSave(); err != nil || !canSave { if canSave, err := guard.CanSave(); err != nil || !canSave {
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -72,7 +72,7 @@ func (dr *dashboardServiceImpl) GetFolderByID(ctx context.Context, id int64) (*m
return nil, toFolderError(err) return nil, toFolderError(err)
} }
g := guardian.New(dashFolder.Id, dr.orgId, dr.user) g := guardian.New(ctx, dashFolder.Id, dr.orgId, dr.user)
if canView, err := g.CanView(); err != nil || !canView { if canView, err := g.CanView(); err != nil || !canView {
if err != nil { if err != nil {
return nil, toFolderError(err) return nil, toFolderError(err)
@ -91,7 +91,7 @@ func (dr *dashboardServiceImpl) GetFolderByUID(ctx context.Context, uid string)
return nil, toFolderError(err) return nil, toFolderError(err)
} }
g := guardian.New(dashFolder.Id, dr.orgId, dr.user) g := guardian.New(ctx, dashFolder.Id, dr.orgId, dr.user)
if canView, err := g.CanView(); err != nil || !canView { if canView, err := g.CanView(); err != nil || !canView {
if err != nil { if err != nil {
return nil, toFolderError(err) return nil, toFolderError(err)
@ -108,7 +108,7 @@ func (dr *dashboardServiceImpl) GetFolderByTitle(ctx context.Context, title stri
return nil, toFolderError(err) return nil, toFolderError(err)
} }
g := guardian.New(dashFolder.Id, dr.orgId, dr.user) g := guardian.New(ctx, dashFolder.Id, dr.orgId, dr.user)
if canView, err := g.CanView(); err != nil || !canView { if canView, err := g.CanView(); err != nil || !canView {
if err != nil { if err != nil {
return nil, toFolderError(err) return nil, toFolderError(err)
@ -200,7 +200,7 @@ func (dr *dashboardServiceImpl) DeleteFolder(ctx context.Context, uid string, fo
return nil, toFolderError(err) return nil, toFolderError(err)
} }
guardian := guardian.New(dashFolder.Id, dr.orgId, dr.user) guardian := guardian.New(ctx, dashFolder.Id, dr.orgId, dr.user)
if canSave, err := guardian.CanSave(); err != nil || !canSave { if canSave, err := guardian.CanSave(); err != nil || !canSave {
if err != nil { if err != nil {
return nil, toFolderError(err) return nil, toFolderError(err)

View File

@ -1,6 +1,7 @@
package guardian package guardian
import ( import (
"context"
"errors" "errors"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
@ -40,15 +41,17 @@ type dashboardGuardianImpl struct {
acl []*models.DashboardAclInfoDTO acl []*models.DashboardAclInfoDTO
teams []*models.TeamDTO teams []*models.TeamDTO
log log.Logger log log.Logger
ctx context.Context
} }
// New factory for creating a new dashboard guardian instance // New factory for creating a new dashboard guardian instance
var New = func(dashId int64, orgId int64, user *models.SignedInUser) DashboardGuardian { var New = func(ctx context.Context, dashId int64, orgId int64, user *models.SignedInUser) DashboardGuardian {
return &dashboardGuardianImpl{ return &dashboardGuardianImpl{
user: user, user: user,
dashId: dashId, dashId: dashId,
orgId: orgId, orgId: orgId,
log: log.New("dashboard.permissions"), log: log.New("dashboard.permissions"),
ctx: ctx,
} }
} }
@ -201,7 +204,7 @@ func (g *dashboardGuardianImpl) GetAcl() ([]*models.DashboardAclInfoDTO, error)
} }
query := models.GetDashboardAclInfoListQuery{DashboardID: g.dashId, OrgID: g.orgId} query := models.GetDashboardAclInfoListQuery{DashboardID: g.dashId, OrgID: g.orgId}
if err := bus.Dispatch(&query); err != nil { if err := bus.DispatchCtx(g.ctx, &query); err != nil {
return nil, err return nil, err
} }
@ -251,6 +254,7 @@ func (g *dashboardGuardianImpl) getTeams() ([]*models.TeamDTO, error) {
} }
query := models.GetTeamsByUserQuery{OrgId: g.orgId, UserId: g.user.UserId} query := models.GetTeamsByUserQuery{OrgId: g.orgId, UserId: g.user.UserId}
// TODO: Use bus.DispatchCtx(g.Ctx, &query) when GetTeamsByUserQuery supports context.
err := bus.Dispatch(&query) err := bus.Dispatch(&query)
g.teams = query.Result g.teams = query.Result
@ -343,7 +347,7 @@ func (g *FakeDashboardGuardian) GetHiddenACL(cfg *setting.Cfg) ([]*models.Dashbo
// nolint:unused // nolint:unused
func MockDashboardGuardian(mock *FakeDashboardGuardian) { func MockDashboardGuardian(mock *FakeDashboardGuardian) {
New = func(dashId int64, orgId int64, user *models.SignedInUser) DashboardGuardian { New = func(_ context.Context, dashId int64, orgId int64, user *models.SignedInUser) DashboardGuardian {
mock.OrgId = orgId mock.OrgId = orgId
mock.DashId = dashId mock.DashId = dashId
mock.User = user mock.User = user

View File

@ -1,6 +1,7 @@
package guardian package guardian
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"runtime" "runtime"
@ -701,7 +702,7 @@ func TestGuardianGetHiddenACL(t *testing.T) {
UserId: 1, UserId: 1,
Login: "user1", Login: "user1",
} }
g := New(dashboardID, orgID, user) g := New(context.Background(), dashboardID, orgID, user)
hiddenACL, err := g.GetHiddenACL(cfg) hiddenACL, err := g.GetHiddenACL(cfg)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -717,7 +718,7 @@ func TestGuardianGetHiddenACL(t *testing.T) {
Login: "user1", Login: "user1",
IsGrafanaAdmin: true, IsGrafanaAdmin: true,
} }
g := New(dashboardID, orgID, user) g := New(context.Background(), dashboardID, orgID, user)
hiddenACL, err := g.GetHiddenACL(cfg) hiddenACL, err := g.GetHiddenACL(cfg)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -751,7 +752,7 @@ func TestGuardianGetAclWithoutDuplicates(t *testing.T) {
UserId: 1, UserId: 1,
Login: "user1", Login: "user1",
} }
g := New(dashboardID, orgID, user) g := New(context.Background(), dashboardID, orgID, user)
acl, err := g.GetACLWithoutDuplicates() acl, err := g.GetACLWithoutDuplicates()
require.NoError(t, err) require.NoError(t, err)

View File

@ -2,6 +2,7 @@ package guardian
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"strings" "strings"
"testing" "testing"
@ -35,7 +36,7 @@ func orgRoleScenario(desc string, t *testing.T, role models.RoleType, fn scenari
OrgId: orgID, OrgId: orgID,
OrgRole: role, OrgRole: role,
} }
guard := New(dashboardID, orgID, user) guard := New(context.Background(), dashboardID, orgID, user)
sc := &scenarioContext{ sc := &scenarioContext{
t: t, t: t,
@ -56,7 +57,7 @@ func apiKeyScenario(desc string, t *testing.T, role models.RoleType, fn scenario
OrgRole: role, OrgRole: role,
ApiKeyId: 10, ApiKeyId: 10,
} }
guard := New(dashboardID, orgID, user) guard := New(context.Background(), dashboardID, orgID, user)
sc := &scenarioContext{ sc := &scenarioContext{
t: t, t: t,
orgRoleScenario: desc, orgRoleScenario: desc,
@ -107,7 +108,7 @@ func permissionScenario(desc string, dashboardID int64, sc *scenarioContext,
}) })
sc.permissionScenario = desc sc.permissionScenario = desc
sc.g = New(dashboardID, sc.givenUser.OrgId, sc.givenUser) sc.g = New(context.Background(), dashboardID, sc.givenUser.OrgId, sc.givenUser)
sc.givenDashboardID = dashboardID sc.givenDashboardID = dashboardID
sc.givenPermissions = permissions sc.givenPermissions = permissions
sc.givenTeams = teams sc.givenTeams = teams

View File

@ -39,7 +39,7 @@ func (l *LibraryElementService) requirePermissionsOnFolder(ctx context.Context,
return err return err
} }
g := guardian.New(folder.Id, user.OrgId, user) g := guardian.New(ctx, folder.Id, user.OrgId, user)
canEdit, err := g.CanEdit() canEdit, err := g.CanEdit()
if err != nil { if err != nil {

View File

@ -68,7 +68,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *models.SignedI
} }
dash := query.Result dash := query.Result
guard := guardian.New(dash.Id, user.OrgId, user) guard := guardian.New(ctx, dash.Id, user.OrgId, user)
if canView, err := guard.CanView(); err != nil || !canView { if canView, err := guard.CanView(); err != nil || !canView {
return models.SubscribeReply{}, backend.SubscribeStreamStatusPermissionDenied, nil return models.SubscribeReply{}, backend.SubscribeStreamStatusPermissionDenied, nil
} }
@ -114,7 +114,7 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, user *models.SignedInU
return models.PublishReply{}, backend.PublishStreamStatusNotFound, nil return models.PublishReply{}, backend.PublishStreamStatusNotFound, nil
} }
guard := guardian.New(query.Result.Id, user.OrgId, user) guard := guardian.New(ctx, query.Result.Id, user.OrgId, user)
canEdit, err := guard.CanEdit() canEdit, err := guard.CanEdit()
if err != nil { if err != nil {
return models.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("internal error") return models.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("internal error")

View File

@ -404,7 +404,7 @@ func (st DBstore) GetNamespaceByTitle(ctx context.Context, namespace string, org
} }
if withCanSave { if withCanSave {
g := guardian.New(folder.Id, orgID, user) g := guardian.New(ctx, folder.Id, orgID, user)
if canSave, err := g.CanSave(); err != nil || !canSave { if canSave, err := g.CanSave(); err != nil || !canSave {
if err != nil { if err != nil {
st.Logger.Error("checking can save permission has failed", "userId", user.UserId, "username", user.Login, "namespace", namespace, "orgId", orgID, "error", err) st.Logger.Error("checking can save permission has failed", "userId", user.UserId, "username", user.Login, "namespace", namespace, "orgId", orgID, "error", err)

View File

@ -8,12 +8,16 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
) )
func init() { func (ss *SQLStore) addDashboardACLQueryAndCommandHandlers() {
bus.AddHandler("sql", GetDashboardAclInfoList) bus.AddHandlerCtx("sql", ss.GetDashboardAclInfoList)
} }
func (ss *SQLStore) UpdateDashboardACL(dashboardID int64, items []*models.DashboardAcl) error { func (ss *SQLStore) UpdateDashboardACL(dashboardID int64, items []*models.DashboardAcl) error {
return ss.WithTransactionalDbSession(context.Background(), func(sess *DBSession) error { return ss.UpdateDashboardACLCtx(context.TODO(), dashboardID, items)
}
func (ss *SQLStore) UpdateDashboardACLCtx(ctx context.Context, dashboardID int64, items []*models.DashboardAcl) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
// delete existing items // delete existing items
_, err := sess.Exec("DELETE FROM dashboard_acl WHERE dashboard_id=?", dashboardID) _, err := sess.Exec("DELETE FROM dashboard_acl WHERE dashboard_id=?", dashboardID)
if err != nil { if err != nil {
@ -47,13 +51,13 @@ func (ss *SQLStore) UpdateDashboardACL(dashboardID int64, items []*models.Dashbo
// 1) Permissions for the dashboard // 1) Permissions for the dashboard
// 2) permissions for its parent folder // 2) permissions for its parent folder
// 3) if no specific permissions have been set for the dashboard or its parent folder then get the default permissions // 3) if no specific permissions have been set for the dashboard or its parent folder then get the default permissions
func GetDashboardAclInfoList(query *models.GetDashboardAclInfoListQuery) error { func (ss *SQLStore) GetDashboardAclInfoList(ctx context.Context, query *models.GetDashboardAclInfoListQuery) error {
var err error outerErr := ss.WithDbSession(ctx, func(dbSession *DBSession) error {
query.Result = make([]*models.DashboardAclInfoDTO, 0)
falseStr := dialect.BooleanStr(false)
falseStr := dialect.BooleanStr(false) if query.DashboardID == 0 {
sql := `SELECT
if query.DashboardID == 0 {
sql := `SELECT
da.id, da.id,
da.org_id, da.org_id,
da.dashboard_id, da.dashboard_id,
@ -69,13 +73,13 @@ func GetDashboardAclInfoList(query *models.GetDashboardAclInfoListQuery) error {
'' as title, '' as title,
'' as slug, '' as slug,
'' as uid,` + '' as uid,` +
falseStr + ` AS is_folder,` + falseStr + ` AS is_folder,` +
falseStr + ` AS inherited falseStr + ` AS inherited
FROM dashboard_acl as da FROM dashboard_acl as da
WHERE da.dashboard_id = -1` WHERE da.dashboard_id = -1`
query.Result = make([]*models.DashboardAclInfoDTO, 0) return dbSession.SQL(sql).Find(&query.Result)
err = x.SQL(sql).Find(&query.Result) }
} else {
rawSQL := ` rawSQL := `
-- get permissions for the dashboard and its parent folder -- get permissions for the dashboard and its parent folder
SELECT SELECT
@ -115,13 +119,16 @@ func GetDashboardAclInfoList(query *models.GetDashboardAclInfoListQuery) error {
ORDER BY da.id ASC ORDER BY da.id ASC
` `
query.Result = make([]*models.DashboardAclInfoDTO, 0) return dbSession.SQL(rawSQL, query.OrgID, query.DashboardID).Find(&query.Result)
err = x.SQL(rawSQL, query.OrgID, query.DashboardID).Find(&query.Result) })
if outerErr != nil {
return outerErr
} }
for _, p := range query.Result { for _, p := range query.Result {
p.PermissionName = p.Permission.String() p.PermissionName = p.Permission.String()
} }
return err return nil
} }

View File

@ -4,6 +4,7 @@
package sqlstore package sqlstore
import ( import (
"context"
"testing" "testing"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
@ -32,7 +33,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
Convey("When reading folder acl should include default acl", func() { Convey("When reading folder acl should include default acl", func() {
query := models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} query := models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1}
err := GetDashboardAclInfoList(&query) err := sqlStore.GetDashboardAclInfoList(context.Background(), &query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)
@ -48,7 +49,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
Convey("When reading dashboard acl should include acl for parent folder", func() { Convey("When reading dashboard acl should include acl for parent folder", func() {
query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1}
err := GetDashboardAclInfoList(&query) err := sqlStore.GetDashboardAclInfoList(context.Background(), &query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)
@ -69,7 +70,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
Convey("When reading dashboard acl should return no acl items", func() { Convey("When reading dashboard acl should return no acl items", func() {
query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1}
err := GetDashboardAclInfoList(&query) err := sqlStore.GetDashboardAclInfoList(context.Background(), &query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 0) So(len(query.Result), ShouldEqual, 0)
@ -88,7 +89,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
Convey("When reading dashboard acl should include acl for parent folder", func() { Convey("When reading dashboard acl should include acl for parent folder", func() {
query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1}
err := GetDashboardAclInfoList(&query) err := sqlStore.GetDashboardAclInfoList(context.Background(), &query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1) So(len(query.Result), ShouldEqual, 1)
@ -107,7 +108,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
Convey("When reading dashboard acl should include acl for parent folder and child", func() { Convey("When reading dashboard acl should include acl for parent folder and child", func() {
query := models.GetDashboardAclInfoListQuery{OrgID: 1, DashboardID: childDash.Id} query := models.GetDashboardAclInfoListQuery{OrgID: 1, DashboardID: childDash.Id}
err := GetDashboardAclInfoList(&query) err := sqlStore.GetDashboardAclInfoList(context.Background(), &query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)
@ -131,7 +132,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
Convey("When reading dashboard acl should include default acl for parent folder and the child acl", func() { Convey("When reading dashboard acl should include default acl for parent folder and the child acl", func() {
query := models.GetDashboardAclInfoListQuery{OrgID: 1, DashboardID: childDash.Id} query := models.GetDashboardAclInfoListQuery{OrgID: 1, DashboardID: childDash.Id}
err := GetDashboardAclInfoList(&query) err := sqlStore.GetDashboardAclInfoList(context.Background(), &query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
defaultPermissionsId := -1 defaultPermissionsId := -1
@ -157,7 +158,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
q1 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} q1 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1}
err = GetDashboardAclInfoList(q1) err = sqlStore.GetDashboardAclInfoList(context.Background(), q1)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id) So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id)
@ -172,7 +173,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
q3 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} q3 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1}
err = GetDashboardAclInfoList(q3) err = sqlStore.GetDashboardAclInfoList(context.Background(), q3)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(q3.Result), ShouldEqual, 0) So(len(q3.Result), ShouldEqual, 0)
}) })
@ -192,7 +193,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
q1 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} q1 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1}
err = GetDashboardAclInfoList(q1) err = sqlStore.GetDashboardAclInfoList(context.Background(), q1)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id) So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id)
So(q1.Result[0].Permission, ShouldEqual, models.PERMISSION_EDIT) So(q1.Result[0].Permission, ShouldEqual, models.PERMISSION_EDIT)
@ -209,7 +210,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
q3 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} q3 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1}
err = GetDashboardAclInfoList(q3) err = sqlStore.GetDashboardAclInfoList(context.Background(), q3)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(q3.Result), ShouldEqual, 1) So(len(q3.Result), ShouldEqual, 1)
So(q3.Result[0].DashboardId, ShouldEqual, savedFolder.Id) So(q3.Result[0].DashboardId, ShouldEqual, savedFolder.Id)
@ -225,7 +226,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
Convey("When reading dashboard acl should return default permissions", func() { Convey("When reading dashboard acl should return default permissions", func() {
query := models.GetDashboardAclInfoListQuery{DashboardID: rootFolderId, OrgID: 1} query := models.GetDashboardAclInfoListQuery{DashboardID: rootFolderId, OrgID: 1}
err := GetDashboardAclInfoList(&query) err := sqlStore.GetDashboardAclInfoList(context.Background(), &query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 2) So(len(query.Result), ShouldEqual, 2)

View File

@ -338,7 +338,7 @@ func TestAccountDataAccess(t *testing.T) {
Convey("Should remove dependent permissions for deleted org user", func() { Convey("Should remove dependent permissions for deleted org user", func() {
permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash1.Id, OrgID: ac1.OrgId} permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash1.Id, OrgID: ac1.OrgId}
err = GetDashboardAclInfoList(permQuery) err = sqlStore.GetDashboardAclInfoList(context.Background(), permQuery)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(permQuery.Result), ShouldEqual, 0) So(len(permQuery.Result), ShouldEqual, 0)
@ -346,7 +346,7 @@ func TestAccountDataAccess(t *testing.T) {
Convey("Should not remove dashboard permissions for same user in another org", func() { Convey("Should not remove dashboard permissions for same user in another org", func() {
permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash2.Id, OrgID: ac3.OrgId} permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash2.Id, OrgID: ac3.OrgId}
err = GetDashboardAclInfoList(permQuery) err = sqlStore.GetDashboardAclInfoList(context.Background(), permQuery)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(permQuery.Result), ShouldEqual, 1) So(len(permQuery.Result), ShouldEqual, 1)

View File

@ -113,6 +113,7 @@ func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bu
ss.addAlertNotificationUidByIdHandler() ss.addAlertNotificationUidByIdHandler()
ss.addPreferencesQueryAndCommandHandlers() ss.addPreferencesQueryAndCommandHandlers()
ss.addDashboardQueryAndCommandHandlers() ss.addDashboardQueryAndCommandHandlers()
ss.addDashboardACLQueryAndCommandHandlers()
ss.addQuotaQueryAndCommandHandlers() ss.addQuotaQueryAndCommandHandlers()
// if err := ss.Reset(); err != nil { // if err := ss.Reset(); err != nil {

View File

@ -262,7 +262,7 @@ func TestTeamCommandsAndQueries(t *testing.T) {
So(err, ShouldEqual, models.ErrTeamNotFound) So(err, ShouldEqual, models.ErrTeamNotFound)
permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: testOrgID} permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: testOrgID}
err = GetDashboardAclInfoList(permQuery) err = sqlStore.GetDashboardAclInfoList(context.Background(), permQuery)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(permQuery.Result), ShouldEqual, 0) So(len(permQuery.Result), ShouldEqual, 0)

View File

@ -261,7 +261,7 @@ func TestUserDataAccess(t *testing.T) {
require.Len(t, query1.Result, 1) require.Len(t, query1.Result, 1)
permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: users[0].OrgId} permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: users[0].OrgId}
err = GetDashboardAclInfoList(permQuery) err = ss.GetDashboardAclInfoList(context.Background(), permQuery)
require.Nil(t, err) require.Nil(t, err)
require.Len(t, permQuery.Result, 0) require.Len(t, permQuery.Result, 0)
@ -347,7 +347,7 @@ func TestUserDataAccess(t *testing.T) {
require.Len(t, query2.Result, 1) require.Len(t, query2.Result, 1)
permQuery = &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: users[0].OrgId} permQuery = &models.GetDashboardAclInfoListQuery{DashboardID: 1, OrgID: users[0].OrgId}
err = GetDashboardAclInfoList(permQuery) err = ss.GetDashboardAclInfoList(context.Background(), permQuery)
require.Nil(t, err) require.Nil(t, err)
require.Len(t, permQuery.Result, 0) require.Len(t, permQuery.Result, 0)