PublicDashboards: Audit table pagination (#69823)
This commit is contained in:
@@ -167,7 +167,7 @@ func (ss *sqlStore) HandleAlertsQuery(ctx context.Context, query *alertmodels.Ge
|
||||
builder.Write(")")
|
||||
}
|
||||
|
||||
builder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW)
|
||||
builder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW, "")
|
||||
|
||||
builder.Write(" ORDER BY name ASC")
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ func getLibraryElements(c context.Context, store db.DB, cfg *setting.Cfg, signed
|
||||
builder.Write(getFromLibraryElementDTOWithMeta(store.GetDialect()))
|
||||
builder.Write(" INNER JOIN dashboard AS dashboard on le.folder_id = dashboard.id AND le.folder_id <> 0")
|
||||
writeParamSelectorSQL(&builder, params...)
|
||||
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW)
|
||||
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW, "")
|
||||
builder.Write(` OR dashboard.id=0`)
|
||||
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryElements); err != nil {
|
||||
return err
|
||||
@@ -372,7 +372,7 @@ func (l *LibraryElementService) getAllLibraryElements(c context.Context, signedI
|
||||
return err
|
||||
}
|
||||
if signedInUser.OrgRole != org.RoleAdmin {
|
||||
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW)
|
||||
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW, "")
|
||||
}
|
||||
if query.SortDirection == search.SortAlphaDesc.Name {
|
||||
builder.Write(" ORDER BY 1 DESC")
|
||||
@@ -603,7 +603,7 @@ func (l *LibraryElementService) getConnections(c context.Context, signedInUser *
|
||||
builder.Write(" INNER JOIN dashboard AS dashboard on lec.connection_id = dashboard.id")
|
||||
builder.Write(` WHERE lec.element_id=?`, element.ID)
|
||||
if signedInUser.OrgRole != org.RoleAdmin {
|
||||
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW)
|
||||
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW, "")
|
||||
}
|
||||
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryElementConnections); err != nil {
|
||||
return err
|
||||
|
||||
@@ -90,7 +90,24 @@ func (api *Api) RegisterAPIEndpoints() {
|
||||
// ListPublicDashboards Gets list of public dashboards by orgId
|
||||
// GET /api/dashboards/public-dashboards
|
||||
func (api *Api) ListPublicDashboards(c *contextmodel.ReqContext) response.Response {
|
||||
resp, err := api.PublicDashboardService.FindAll(c.Req.Context(), c.SignedInUser, c.OrgID)
|
||||
perPage := c.QueryInt("perpage")
|
||||
if perPage <= 0 {
|
||||
perPage = 1000
|
||||
}
|
||||
|
||||
page := c.QueryInt("page")
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
resp, err := api.PublicDashboardService.FindAllWithPagination(c.Req.Context(), &PublicDashboardListQuery{
|
||||
OrgID: c.OrgID,
|
||||
Query: c.Query("query"),
|
||||
Page: page,
|
||||
Limit: perPage,
|
||||
User: c.SignedInUser,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
@@ -89,19 +89,21 @@ func TestAPIFeatureFlag(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAPIListPublicDashboard(t *testing.T) {
|
||||
successResp := []PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "1234asdfasdf",
|
||||
AccessToken: "asdfasdf",
|
||||
DashboardUid: "abc1234",
|
||||
IsEnabled: true,
|
||||
successResp := &PublicDashboardListResponseWithPagination{
|
||||
PublicDashboards: []*PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "1234asdfasdf",
|
||||
AccessToken: "asdfasdf",
|
||||
DashboardUid: "abc1234",
|
||||
IsEnabled: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
User *user.SignedInUser
|
||||
Response []PublicDashboardListResponse
|
||||
Response *PublicDashboardListResponseWithPagination
|
||||
ResponseErr error
|
||||
ExpectedHttpResponse int
|
||||
}{
|
||||
@@ -131,7 +133,7 @@ func TestAPIListPublicDashboard(t *testing.T) {
|
||||
for _, test := range testCases {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
service := publicdashboards.NewFakePublicDashboardService(t)
|
||||
service.On("FindAll", mock.Anything, mock.Anything, mock.Anything).
|
||||
service.On("FindAllWithPagination", mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(test.Response, test.ResponseErr).Maybe()
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
@@ -143,10 +145,10 @@ func TestAPIListPublicDashboard(t *testing.T) {
|
||||
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
|
||||
|
||||
if test.ExpectedHttpResponse == http.StatusOK {
|
||||
var jsonResp []PublicDashboardListResponse
|
||||
var jsonResp PublicDashboardListResponseWithPagination
|
||||
err := json.Unmarshal(response.Body.Bytes(), &jsonResp)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, jsonResp[0].Uid, "1234asdfasdf")
|
||||
assert.Equal(t, jsonResp.PublicDashboards[0].Uid, "1234asdfasdf")
|
||||
}
|
||||
|
||||
if test.ResponseErr != nil {
|
||||
@@ -155,7 +157,7 @@ func TestAPIListPublicDashboard(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Internal server error", errResp.Message)
|
||||
assert.Equal(t, "publicdashboards.internalServerError", errResp.MessageID)
|
||||
service.AssertNotCalled(t, "FindAll")
|
||||
service.AssertNotCalled(t, "FindAllWithPagination")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T)
|
||||
annotationsService := annotationstest.NewFakeAnnotationsRepo()
|
||||
|
||||
// create public dashboard
|
||||
store := publicdashboardsStore.ProvideStore(db)
|
||||
store := publicdashboardsStore.ProvideStore(db, db.Cfg, featuremgmt.WithFeatures())
|
||||
cfg := setting.NewCfg()
|
||||
ac := acmock.New()
|
||||
ws := publicdashboardsService.ProvideServiceWrapper(store)
|
||||
|
||||
@@ -7,9 +7,13 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
// Define the storage implementation. We're generating the mock implementation
|
||||
@@ -17,6 +21,8 @@ import (
|
||||
type PublicDashboardStoreImpl struct {
|
||||
sqlStore db.DB
|
||||
log log.Logger
|
||||
cfg *setting.Cfg
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
var LogPrefix = "publicdashboards.store"
|
||||
@@ -26,25 +32,54 @@ var LogPrefix = "publicdashboards.store"
|
||||
var _ publicdashboards.Store = (*PublicDashboardStoreImpl)(nil)
|
||||
|
||||
// Factory used by wire to dependency injection
|
||||
func ProvideStore(sqlStore db.DB) *PublicDashboardStoreImpl {
|
||||
func ProvideStore(sqlStore db.DB, cfg *setting.Cfg, features featuremgmt.FeatureToggles) *PublicDashboardStoreImpl {
|
||||
return &PublicDashboardStoreImpl{
|
||||
sqlStore: sqlStore,
|
||||
log: log.New(LogPrefix),
|
||||
cfg: cfg,
|
||||
features: features,
|
||||
}
|
||||
}
|
||||
|
||||
// FindAll Returns a list of public dashboards by orgId
|
||||
func (d *PublicDashboardStoreImpl) FindAll(ctx context.Context, orgId int64) ([]PublicDashboardListResponse, error) {
|
||||
resp := make([]PublicDashboardListResponse, 0)
|
||||
// FindAllWithPagination Returns a list of public dashboards by orgId, based on permissions and with pagination
|
||||
func (d *PublicDashboardStoreImpl) FindAllWithPagination(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error) {
|
||||
resp := &PublicDashboardListResponseWithPagination{
|
||||
PublicDashboards: make([]*PublicDashboardListResponse, 0),
|
||||
TotalCount: 0,
|
||||
}
|
||||
|
||||
err := d.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
sess.Table("dashboard_public").Select(
|
||||
"dashboard_public.uid, dashboard_public.access_token, dashboard.uid as dashboard_uid, dashboard_public.is_enabled, dashboard.title").
|
||||
Join("LEFT", "dashboard", "dashboard.uid = dashboard_public.dashboard_uid AND dashboard.org_id = dashboard_public.org_id").
|
||||
Where("dashboard_public.org_id = ?", orgId).
|
||||
OrderBy(" dashboard.title IS NULL, dashboard.title ASC")
|
||||
recursiveQueriesAreSupported, err := d.sqlStore.RecursiveQueriesAreSupported()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := sess.Find(&resp)
|
||||
pubdashBuilder := db.NewSqlBuilder(d.cfg, d.features, d.sqlStore.GetDialect(), recursiveQueriesAreSupported)
|
||||
pubdashBuilder.Write("SELECT dashboard_public.uid, dashboard_public.access_token, dashboard.uid as dashboard_uid, dashboard_public.is_enabled, dashboard.title")
|
||||
pubdashBuilder.Write(" FROM dashboard_public")
|
||||
pubdashBuilder.Write(" JOIN dashboard ON dashboard.uid = dashboard_public.dashboard_uid AND dashboard.org_id = dashboard_public.org_id")
|
||||
pubdashBuilder.Write(` WHERE dashboard_public.org_id = ?`, query.OrgID)
|
||||
if query.User.OrgRole != org.RoleAdmin {
|
||||
pubdashBuilder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW, searchstore.TypeDashboard)
|
||||
}
|
||||
pubdashBuilder.Write(" ORDER BY dashboard.title")
|
||||
pubdashBuilder.Write(d.sqlStore.GetDialect().LimitOffset(int64(query.Limit), int64(query.Offset)))
|
||||
|
||||
counterBuilder := db.NewSqlBuilder(d.cfg, d.features, d.sqlStore.GetDialect(), recursiveQueriesAreSupported)
|
||||
counterBuilder.Write("SELECT COUNT(*)")
|
||||
counterBuilder.Write(" FROM dashboard_public")
|
||||
counterBuilder.Write(" JOIN dashboard ON dashboard.uid = dashboard_public.dashboard_uid AND dashboard.org_id = dashboard_public.org_id")
|
||||
counterBuilder.Write(` WHERE dashboard_public.org_id = ?`, query.OrgID)
|
||||
if query.User.OrgRole != org.RoleAdmin {
|
||||
counterBuilder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW, searchstore.TypeDashboard)
|
||||
}
|
||||
|
||||
err = d.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
err := sess.SQL(pubdashBuilder.GetSQLString(), pubdashBuilder.GetParams()...).Find(&resp.PublicDashboards)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sess.SQL(counterBuilder.GetSQLString(), counterBuilder.GetParams()...).Get(&resp.TotalCount)
|
||||
return err
|
||||
})
|
||||
|
||||
|
||||
@@ -2,18 +2,24 @@ package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -34,38 +40,122 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
sqlStore, cfg := db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := ProvideStore(sqlStore)
|
||||
|
||||
var sqlStore *sqlstore.SQLStore
|
||||
var cfg *setting.Cfg
|
||||
|
||||
var aDash *dashboards.Dashboard
|
||||
var bDash *dashboards.Dashboard
|
||||
var cDash *dashboards.Dashboard
|
||||
|
||||
var aPublicDash *PublicDashboard
|
||||
var bPublicDash *PublicDashboard
|
||||
var cPublicDash *PublicDashboard
|
||||
|
||||
var orgId int64 = 1
|
||||
|
||||
bDash := insertTestDashboard(t, dashboardStore, "b", orgId, 0, true)
|
||||
aDash := insertTestDashboard(t, dashboardStore, "a", orgId, 0, true)
|
||||
cDash := insertTestDashboard(t, dashboardStore, "c", orgId, 0, true)
|
||||
var publicdashboardStore *PublicDashboardStoreImpl
|
||||
|
||||
// these are in order of how they should be returned from ListPUblicDashboards
|
||||
a := insertPublicDashboard(t, publicdashboardStore, aDash.UID, orgId, false, PublicShareType)
|
||||
b := insertPublicDashboard(t, publicdashboardStore, bDash.UID, orgId, true, PublicShareType)
|
||||
c := insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
|
||||
setup := func() {
|
||||
sqlStore, cfg = db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore = ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
|
||||
// this is case that can happen as of now, however, postgres and mysql sort
|
||||
// null in the exact opposite fashion and there is no shared syntax to sort
|
||||
// nulls in the same way in all 3 db's.
|
||||
//d := insertPublicDashboard(t, publicdashboardStore, "missing", orgId, false)
|
||||
bDash = insertTestDashboard(t, dashboardStore, "b", orgId, 0, false)
|
||||
aDash = insertTestDashboard(t, dashboardStore, "a", orgId, 0, false)
|
||||
cDash = insertTestDashboard(t, dashboardStore, "c", orgId, 0, false)
|
||||
|
||||
// should not be included in response
|
||||
_ = insertPublicDashboard(t, publicdashboardStore, "wrongOrgId", 777, false, PublicShareType)
|
||||
// these are in order of how they should be returned from ListPUblicDashboards
|
||||
aPublicDash = insertPublicDashboard(t, publicdashboardStore, aDash.UID, orgId, false, PublicShareType)
|
||||
bPublicDash = insertPublicDashboard(t, publicdashboardStore, bDash.UID, orgId, true, PublicShareType)
|
||||
cPublicDash = insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
|
||||
}
|
||||
|
||||
resp, err := publicdashboardStore.FindAll(context.Background(), orgId)
|
||||
require.NoError(t, err)
|
||||
t.Run("FindAllWithPagination will return dashboard list based on orgId with pagination", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
assert.Len(t, resp, 3)
|
||||
assert.Equal(t, resp[0].Uid, a.Uid)
|
||||
assert.Equal(t, resp[1].Uid, b.Uid)
|
||||
assert.Equal(t, resp[2].Uid, c.Uid)
|
||||
// should not be included in response
|
||||
_ = insertPublicDashboard(t, publicdashboardStore, "wrongOrgId", 777, false, PublicShareType)
|
||||
|
||||
permissions := []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", aDash.UID)},
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", bDash.UID)},
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", cDash.UID)},
|
||||
}
|
||||
|
||||
err := insertPermissions(sqlStore, orgId, "viewer", permissions)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}},
|
||||
OrgID: orgId,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
Offset: 0,
|
||||
}
|
||||
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, resp.PublicDashboards, 3)
|
||||
assert.Equal(t, resp.PublicDashboards[0].Uid, aPublicDash.Uid)
|
||||
assert.Equal(t, resp.PublicDashboards[1].Uid, bPublicDash.Uid)
|
||||
assert.Equal(t, resp.PublicDashboards[2].Uid, cPublicDash.Uid)
|
||||
assert.Equal(t, resp.TotalCount, int64(3))
|
||||
})
|
||||
|
||||
t.Run("FindAllWithPagination will return dashboard list based on read permissions with pagination", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
permissions := []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", aDash.UID)},
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", cDash.UID)},
|
||||
}
|
||||
|
||||
err := insertPermissions(sqlStore, orgId, "viewer", permissions)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}},
|
||||
OrgID: orgId,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
Offset: 0,
|
||||
}
|
||||
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, resp.PublicDashboards, 2)
|
||||
assert.Equal(t, resp.PublicDashboards[0].Uid, aPublicDash.Uid)
|
||||
assert.Equal(t, resp.PublicDashboards[1].Uid, cPublicDash.Uid)
|
||||
assert.Equal(t, resp.TotalCount, int64(2))
|
||||
})
|
||||
|
||||
t.Run("FindAllWithPagination will return empty dashboard list based on read permissions with pagination", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
permissions := []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:another-dashboard-uid"},
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:another-dashboard-2-uid"},
|
||||
}
|
||||
|
||||
err := insertPermissions(sqlStore, orgId, "viewer", permissions)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}},
|
||||
OrgID: orgId,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
Offset: 0,
|
||||
}
|
||||
resp, err := publicdashboardStore.FindAllWithPagination(context.Background(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, resp.PublicDashboards, 0)
|
||||
assert.Equal(t, resp.TotalCount, int64(0))
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntegrationFindDashboard(t *testing.T) {
|
||||
@@ -84,7 +174,7 @@ func TestIntegrationFindDashboard(t *testing.T) {
|
||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
dashboardStore = store
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
}
|
||||
|
||||
@@ -114,7 +204,7 @@ func TestIntegrationExistsEnabledByAccessToken(t *testing.T) {
|
||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
dashboardStore = store
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
}
|
||||
t.Run("ExistsEnabledByAccessToken will return true when at least one public dashboard has a matching access token", func(t *testing.T) {
|
||||
@@ -187,7 +277,7 @@ func TestIntegrationExistsEnabledByDashboardUid(t *testing.T) {
|
||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
dashboardStore = store
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
}
|
||||
|
||||
@@ -252,7 +342,7 @@ func TestIntegrationFindByDashboardUid(t *testing.T) {
|
||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
dashboardStore = store
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
}
|
||||
|
||||
@@ -319,7 +409,7 @@ func TestIntegrationFindByAccessToken(t *testing.T) {
|
||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
}
|
||||
|
||||
@@ -389,7 +479,7 @@ func TestIntegrationCreatePublicDashboard(t *testing.T) {
|
||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
dashboardStore = store
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, true)
|
||||
insertPublicDashboard(t, publicdashboardStore, savedDashboard2.UID, savedDashboard2.OrgID, false, PublicShareType)
|
||||
@@ -468,7 +558,7 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
anotherSavedDashboard = insertTestDashboard(t, dashboardStore, "test another Dashie", 1, 0, true)
|
||||
}
|
||||
@@ -572,7 +662,7 @@ func TestIntegrationGetOrgIdByAccessToken(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
}
|
||||
t.Run("GetOrgIdByAccessToken will OrgId when enabled", func(t *testing.T) {
|
||||
@@ -644,7 +734,7 @@ func TestIntegrationDelete(t *testing.T) {
|
||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||
savedPublicDashboard = insertPublicDashboard(t, publicdashboardStore, savedDashboard.UID, savedDashboard.OrgID, true, PublicShareType)
|
||||
}
|
||||
@@ -675,7 +765,7 @@ func TestGetDashboardByFolder(t *testing.T) {
|
||||
t.Run("returns nil when dashboard is not a folder", func(t *testing.T) {
|
||||
sqlStore, _ := db.InitTestDBwithCfg(t)
|
||||
dashboard := &dashboards.Dashboard{IsFolder: false}
|
||||
store := ProvideStore(sqlStore)
|
||||
store := ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
pubdashes, err := store.FindByDashboardFolder(context.Background(), dashboard)
|
||||
|
||||
require.NoError(t, err)
|
||||
@@ -684,7 +774,7 @@ func TestGetDashboardByFolder(t *testing.T) {
|
||||
|
||||
t.Run("returns nil when dashboard is nil", func(t *testing.T) {
|
||||
sqlStore, _ := db.InitTestDBwithCfg(t)
|
||||
store := ProvideStore(sqlStore)
|
||||
store := ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
pubdashes, err := store.FindByDashboardFolder(context.Background(), nil)
|
||||
|
||||
require.NoError(t, err)
|
||||
@@ -696,7 +786,7 @@ func TestGetDashboardByFolder(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
pubdashStore := ProvideStore(sqlStore)
|
||||
pubdashStore := ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "title", 1, 1, true, PublicShareType)
|
||||
pubdash := insertPublicDashboard(t, pubdashStore, dashboard.UID, dashboard.OrgID, true, PublicShareType)
|
||||
dashboard2 := insertTestDashboard(t, dashboardStore, "title", 1, 2, true, PublicShareType)
|
||||
@@ -729,7 +819,7 @@ func TestGetMetrics(t *testing.T) {
|
||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
dashboardStore = store
|
||||
publicdashboardStore = ProvideStore(sqlStore)
|
||||
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, false)
|
||||
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, false)
|
||||
savedDashboard3 = insertTestDashboard(t, dashboardStore, "testDashie3", 2, 0, false)
|
||||
@@ -827,3 +917,50 @@ func insertPublicDashboard(t *testing.T, publicdashboardStore *PublicDashboardSt
|
||||
|
||||
return pubdash
|
||||
}
|
||||
|
||||
func insertPermissions(sqlStore *sqlstore.SQLStore, orgId int64, role string, permissions []accesscontrol.Permission) error {
|
||||
return sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||
newRole := &accesscontrol.Role{
|
||||
OrgID: orgId,
|
||||
UID: fmt.Sprintf("basic_%s", role),
|
||||
Name: fmt.Sprintf("basic:%s", role),
|
||||
Updated: time.Now(),
|
||||
Created: time.Now(),
|
||||
}
|
||||
_, err := sess.Insert(newRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sess.Insert(accesscontrol.BuiltinRole{
|
||||
OrgID: orgId,
|
||||
RoleID: newRole.ID,
|
||||
Role: strings.ToUpper(role[:1]) + role[1:],
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range permissions {
|
||||
permissions[i].RoleID = newRole.ID
|
||||
permissions[i].Created = time.Now()
|
||||
permissions[i].Updated = time.Now()
|
||||
}
|
||||
|
||||
_, err = sess.InsertMulti(&permissions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sess.Insert(accesscontrol.UserRole{
|
||||
OrgID: orgId,
|
||||
RoleID: newRole.ID,
|
||||
UserID: 1,
|
||||
Created: time.Now(),
|
||||
})
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/dashboard"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
// PublicDashboardErr represents a dashboard error.
|
||||
@@ -103,6 +104,22 @@ func (pd PublicDashboard) TableName() string {
|
||||
return "dashboard_public"
|
||||
}
|
||||
|
||||
type PublicDashboardListQuery struct {
|
||||
OrgID int64
|
||||
Query string
|
||||
Page int
|
||||
Limit int
|
||||
Offset int
|
||||
User *user.SignedInUser
|
||||
}
|
||||
|
||||
type PublicDashboardListResponseWithPagination struct {
|
||||
PublicDashboards []*PublicDashboardListResponse `json:"publicDashboards"`
|
||||
TotalCount int64 `json:"totalCount"`
|
||||
Page int `json:"page"`
|
||||
PerPage int `json:"perPage"`
|
||||
}
|
||||
|
||||
type PublicDashboardListResponse struct {
|
||||
Uid string `json:"uid" xorm:"uid"`
|
||||
AccessToken string `json:"accessToken" xorm:"access_token"`
|
||||
|
||||
@@ -139,22 +139,22 @@ func (_m *FakePublicDashboardService) Find(ctx context.Context, uid string) (*mo
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FindAll provides a mock function with given fields: ctx, u, orgId
|
||||
func (_m *FakePublicDashboardService) FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]models.PublicDashboardListResponse, error) {
|
||||
ret := _m.Called(ctx, u, orgId)
|
||||
// FindAllWithPagination provides a mock function with given fields: ctx, query
|
||||
func (_m *FakePublicDashboardService) FindAllWithPagination(ctx context.Context, query *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
var r0 []models.PublicDashboardListResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, int64) []models.PublicDashboardListResponse); ok {
|
||||
r0 = rf(ctx, u, orgId)
|
||||
var r0 *models.PublicDashboardListResponseWithPagination
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.PublicDashboardListQuery) *models.PublicDashboardListResponseWithPagination); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]models.PublicDashboardListResponse)
|
||||
r0 = ret.Get(0).(*models.PublicDashboardListResponseWithPagination)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *user.SignedInUser, int64) error); ok {
|
||||
r1 = rf(ctx, u, orgId)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *models.PublicDashboardListQuery) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -123,22 +123,22 @@ func (_m *FakePublicDashboardStore) Find(ctx context.Context, uid string) (*mode
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FindAll provides a mock function with given fields: ctx, orgId
|
||||
func (_m *FakePublicDashboardStore) FindAll(ctx context.Context, orgId int64) ([]models.PublicDashboardListResponse, error) {
|
||||
ret := _m.Called(ctx, orgId)
|
||||
// FindAllWithPagination provides a mock function with given fields: ctx, query
|
||||
func (_m *FakePublicDashboardStore) FindAllWithPagination(ctx context.Context, query *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
var r0 []models.PublicDashboardListResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) []models.PublicDashboardListResponse); ok {
|
||||
r0 = rf(ctx, orgId)
|
||||
var r0 *models.PublicDashboardListResponseWithPagination
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *models.PublicDashboardListQuery) *models.PublicDashboardListResponseWithPagination); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]models.PublicDashboardListResponse)
|
||||
r0 = ret.Get(0).(*models.PublicDashboardListResponseWithPagination)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
|
||||
r1 = rf(ctx, orgId)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *models.PublicDashboardListQuery) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ type Service interface {
|
||||
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||
FindAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error)
|
||||
FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, error)
|
||||
FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]PublicDashboardListResponse, error)
|
||||
FindAllWithPagination(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error)
|
||||
Find(ctx context.Context, uid string) (*PublicDashboard, error)
|
||||
Create(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
||||
Update(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
||||
@@ -52,7 +52,7 @@ type Store interface {
|
||||
FindByAccessToken(ctx context.Context, accessToken string) (*PublicDashboard, error)
|
||||
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||
FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, error)
|
||||
FindAll(ctx context.Context, orgId int64) ([]PublicDashboardListResponse, error)
|
||||
FindAllWithPagination(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error)
|
||||
Create(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
|
||||
Update(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
|
||||
Delete(ctx context.Context, uid string) (int64, error)
|
||||
|
||||
@@ -663,7 +663,7 @@ func TestGetQueryDataResponse(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
fakeQueryService := &query.FakeQueryService{}
|
||||
fakeQueryService.On("QueryData", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&backend.QueryDataResponse{}, nil)
|
||||
@@ -1109,7 +1109,7 @@ func TestGetMetricRequest(t *testing.T) {
|
||||
sqlStore := db.InitTestDB(t)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
publicDashboard := &PublicDashboard{
|
||||
Uid: "1",
|
||||
@@ -1194,7 +1194,7 @@ func TestBuildMetricRequest(t *testing.T) {
|
||||
sqlStore := db.InitTestDB(t)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
nonPublicDashboard := insertTestDashboard(t, dashboardStore, "testNonPublicDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
|
||||
@@ -276,14 +276,18 @@ func (pd *PublicDashboardServiceImpl) NewPublicDashboardAccessToken(ctx context.
|
||||
return "", ErrInternalServerError.Errorf("failed to generate a unique accessToken for public dashboard")
|
||||
}
|
||||
|
||||
// FindAll Returns a list of public dashboards by orgId
|
||||
func (pd *PublicDashboardServiceImpl) FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]PublicDashboardListResponse, error) {
|
||||
publicDashboards, err := pd.store.FindAll(ctx, orgId)
|
||||
// FindAllWithPagination Returns a list of public dashboards by orgId, based on permissions and with pagination
|
||||
func (pd *PublicDashboardServiceImpl) FindAllWithPagination(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error) {
|
||||
query.Offset = query.Limit * (query.Page - 1)
|
||||
resp, err := pd.store.FindAllWithPagination(ctx, query)
|
||||
if err != nil {
|
||||
return nil, ErrInternalServerError.Errorf("FindAll: %w", err)
|
||||
return nil, ErrInternalServerError.Errorf("FindAllWithPagination: %w", err)
|
||||
}
|
||||
|
||||
return pd.filterDashboardsByPermissions(ctx, u, publicDashboards)
|
||||
resp.Page = query.Page
|
||||
resp.PerPage = query.Limit
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (pd *PublicDashboardServiceImpl) ExistsEnabledByDashboardUid(ctx context.Context, dashboardUid string) (bool, error) {
|
||||
@@ -371,25 +375,6 @@ func (pd *PublicDashboardServiceImpl) logIsEnabledChanged(existingPubdash *Publi
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out dashboards that user does not have read access to
|
||||
func (pd *PublicDashboardServiceImpl) filterDashboardsByPermissions(ctx context.Context, u *user.SignedInUser, publicDashboards []PublicDashboardListResponse) ([]PublicDashboardListResponse, error) {
|
||||
result := make([]PublicDashboardListResponse, 0)
|
||||
|
||||
for i := range publicDashboards {
|
||||
hasAccess, err := pd.ac.Evaluate(ctx, u, accesscontrol.EvalPermission(dashboards.ActionDashboardsRead, dashboards.ScopeDashboardsProvider.GetResourceScopeUID(publicDashboards[i].DashboardUid)))
|
||||
// If original dashboard does not exist, the public dashboard is an orphan. We want to list it anyway
|
||||
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
return nil, ErrInternalServerError.Errorf("filterDashboardsByPermissions: error evaluating permissions %w", err)
|
||||
}
|
||||
|
||||
// If user has access to the original dashboard or the dashboard does not exist, add the pubdash to the result
|
||||
if hasAccess || errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
result = append(result, publicDashboards[i])
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Checks to see if PublicDashboard.ExistsEnabledByDashboardUid is true on create or changed on update
|
||||
func publicDashboardIsEnabledChanged(existingPubdash *PublicDashboard, newPubdash *PublicDashboard) bool {
|
||||
// creating dashboard, enabled true
|
||||
|
||||
@@ -195,7 +195,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
|
||||
@@ -285,7 +285,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
|
||||
@@ -325,7 +325,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
|
||||
@@ -359,7 +359,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
templateVars := make([]map[string]interface{}, 1)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, templateVars, nil)
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
@@ -474,7 +474,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
|
||||
@@ -519,7 +519,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
|
||||
@@ -588,7 +588,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
@@ -686,7 +686,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
quotaService := quotatest.New(false, nil)
|
||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||
require.NoError(t, err)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
|
||||
@@ -915,152 +915,15 @@ func TestDashboardEnabledChanged(t *testing.T) {
|
||||
func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
u *user.SignedInUser
|
||||
orgId int64
|
||||
query *PublicDashboardListQuery
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args args
|
||||
evaluateFunc func(c context.Context, u *user.SignedInUser, e accesscontrol.Evaluator) (bool, error)
|
||||
want []PublicDashboardListResponse
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "should return empty list when user does not have permissions to read any dashboard",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
u: &user.SignedInUser{OrgID: 1},
|
||||
orgId: 1,
|
||||
},
|
||||
want: []PublicDashboardListResponse{},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should return all dashboards when has permissions",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
u: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: {"dashboards:read": {
|
||||
"dashboards:uid:0S6TmO67z", "dashboards:uid:1S6TmO67z", "dashboards:uid:2S6TmO67z", "dashboards:uid:9S6TmO67z",
|
||||
}}},
|
||||
},
|
||||
orgId: 1,
|
||||
},
|
||||
want: []PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "0GwW7mgVk",
|
||||
AccessToken: "0b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "0S6TmO67z",
|
||||
Title: "my zero dashboard",
|
||||
IsEnabled: true,
|
||||
},
|
||||
{
|
||||
Uid: "1GwW7mgVk",
|
||||
AccessToken: "1b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "1S6TmO67z",
|
||||
Title: "my first dashboard",
|
||||
IsEnabled: true,
|
||||
},
|
||||
{
|
||||
Uid: "2GwW7mgVk",
|
||||
AccessToken: "2b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "2S6TmO67z",
|
||||
Title: "my second dashboard",
|
||||
IsEnabled: false,
|
||||
},
|
||||
{
|
||||
Uid: "9GwW7mgVk",
|
||||
AccessToken: "deletedashboardaccesstoken",
|
||||
DashboardUid: "9S6TmO67z",
|
||||
Title: "",
|
||||
IsEnabled: true,
|
||||
},
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should return only dashboards with permissions",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
u: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
||||
},
|
||||
orgId: 1,
|
||||
},
|
||||
want: []PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "0GwW7mgVk",
|
||||
AccessToken: "0b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "0S6TmO67z",
|
||||
Title: "my zero dashboard",
|
||||
IsEnabled: true,
|
||||
},
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should return orphaned public dashboards",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
u: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
||||
},
|
||||
orgId: 1,
|
||||
},
|
||||
evaluateFunc: func(c context.Context, u *user.SignedInUser, e accesscontrol.Evaluator) (bool, error) {
|
||||
return false, dashboards.ErrDashboardNotFound
|
||||
},
|
||||
want: []PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "0GwW7mgVk",
|
||||
AccessToken: "0b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "0S6TmO67z",
|
||||
Title: "my zero dashboard",
|
||||
IsEnabled: true,
|
||||
},
|
||||
{
|
||||
Uid: "1GwW7mgVk",
|
||||
AccessToken: "1b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "1S6TmO67z",
|
||||
Title: "my first dashboard",
|
||||
IsEnabled: true,
|
||||
},
|
||||
{
|
||||
Uid: "2GwW7mgVk",
|
||||
AccessToken: "2b458cb7fe7f42c68712078bcacee6e3",
|
||||
DashboardUid: "2S6TmO67z",
|
||||
Title: "my second dashboard",
|
||||
IsEnabled: false,
|
||||
},
|
||||
{
|
||||
Uid: "9GwW7mgVk",
|
||||
AccessToken: "deletedashboardaccesstoken",
|
||||
DashboardUid: "9S6TmO67z",
|
||||
Title: "",
|
||||
IsEnabled: true,
|
||||
},
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "errors different than not data found should be returned",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
u: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
||||
},
|
||||
orgId: 1,
|
||||
},
|
||||
evaluateFunc: func(c context.Context, u *user.SignedInUser, e accesscontrol.Evaluator) (bool, error) {
|
||||
return false, dashboards.ErrDashboardCorrupt
|
||||
},
|
||||
want: nil,
|
||||
wantErr: assert.Error,
|
||||
},
|
||||
type mockResponse struct {
|
||||
PublicDashboardListResponseWithPagination *PublicDashboardListResponseWithPagination
|
||||
Err error
|
||||
}
|
||||
|
||||
mockedDashboards := []PublicDashboardListResponse{
|
||||
mockedDashboards := []*PublicDashboardListResponse{
|
||||
{
|
||||
Uid: "0GwW7mgVk",
|
||||
AccessToken: "0b458cb7fe7f42c68712078bcacee6e3",
|
||||
@@ -1091,9 +954,62 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
store := NewFakePublicDashboardStore(t)
|
||||
store.On("FindAll", mock.Anything, mock.Anything).
|
||||
Return(mockedDashboards, nil)
|
||||
testCases := []struct {
|
||||
name string
|
||||
args args
|
||||
want *PublicDashboardListResponseWithPagination
|
||||
mockResponse *mockResponse
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "should return correct pagination response",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
query: &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
||||
},
|
||||
OrgID: 1,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
},
|
||||
},
|
||||
mockResponse: &mockResponse{
|
||||
PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{
|
||||
TotalCount: int64(len(mockedDashboards)),
|
||||
PublicDashboards: mockedDashboards,
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
want: &PublicDashboardListResponseWithPagination{
|
||||
Page: 1,
|
||||
PerPage: 50,
|
||||
TotalCount: int64(len(mockedDashboards)),
|
||||
PublicDashboards: mockedDashboards,
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "should return error when store returns error",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
query: &PublicDashboardListQuery{
|
||||
User: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
||||
},
|
||||
OrgID: 1,
|
||||
Page: 1,
|
||||
Limit: 50,
|
||||
},
|
||||
},
|
||||
mockResponse: &mockResponse{
|
||||
PublicDashboardListResponseWithPagination: nil,
|
||||
Err: errors.New("an err"),
|
||||
},
|
||||
want: nil,
|
||||
wantErr: assert.Error,
|
||||
},
|
||||
}
|
||||
|
||||
ac := tests.SetupMockAccesscontrol(t,
|
||||
func(c context.Context, siu *user.SignedInUser, _ accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
||||
@@ -1102,21 +1018,23 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||
false,
|
||||
)
|
||||
|
||||
pd := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
store: store,
|
||||
ac: ac,
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ac.EvaluateFunc = tt.evaluateFunc
|
||||
store := NewFakePublicDashboardStore(t)
|
||||
store.On("FindAllWithPagination", mock.Anything, mock.Anything).
|
||||
Return(tt.mockResponse.PublicDashboardListResponseWithPagination, tt.mockResponse.Err)
|
||||
|
||||
got, err := pd.FindAll(tt.args.ctx, tt.args.u, tt.args.orgId)
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("FindAll(%v, %v, %v)", tt.args.ctx, tt.args.u, tt.args.orgId)) {
|
||||
pd := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
store: store,
|
||||
ac: ac,
|
||||
}
|
||||
|
||||
got, err := pd.FindAllWithPagination(tt.args.ctx, tt.args.query)
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("FindAllWithPagination(%v, %v)", tt.args.ctx, tt.args.query)) {
|
||||
return
|
||||
}
|
||||
assert.Equalf(t, tt.want, got, "FindAll(%v, %v, %v)", tt.args.ctx, tt.args.u, tt.args.orgId)
|
||||
assert.Equalf(t, tt.want, got, "FindAllWithPagination(%v, %v)", tt.args.ctx, tt.args.query)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user