mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PublicDashboards: Audit table pagination (#69823)
This commit is contained in:
parent
ed5a697825
commit
ee73d41d24
@ -60,7 +60,7 @@ func (sb *SQLBuilder) AddParams(params ...interface{}) {
|
|||||||
sb.params = append(sb.params, params...)
|
sb.params = append(sb.params, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, permission dashboards.PermissionType) {
|
func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, permission dashboards.PermissionType, queryType string) {
|
||||||
var (
|
var (
|
||||||
sql string
|
sql string
|
||||||
params []interface{}
|
params []interface{}
|
||||||
@ -68,7 +68,7 @@ func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, pe
|
|||||||
recQryParams []interface{}
|
recQryParams []interface{}
|
||||||
)
|
)
|
||||||
if !ac.IsDisabled(sb.cfg) {
|
if !ac.IsDisabled(sb.cfg) {
|
||||||
filterRBAC := permissions.NewAccessControlDashboardPermissionFilter(user, permission, "", sb.features, sb.recursiveQueriesAreSupported)
|
filterRBAC := permissions.NewAccessControlDashboardPermissionFilter(user, permission, queryType, sb.features, sb.recursiveQueriesAreSupported)
|
||||||
sql, params = filterRBAC.Where()
|
sql, params = filterRBAC.Where()
|
||||||
recQry, recQryParams = filterRBAC.With()
|
recQry, recQryParams = filterRBAC.With()
|
||||||
} else {
|
} else {
|
||||||
|
@ -480,7 +480,7 @@ func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, acl
|
|||||||
|
|
||||||
var res []*dashboardResponse
|
var res []*dashboardResponse
|
||||||
builder.Write("SELECT * FROM dashboard WHERE true")
|
builder.Write("SELECT * FROM dashboard WHERE true")
|
||||||
builder.WriteDashboardPermissionFilter(signedInUser, search.RequiredPermission)
|
builder.WriteDashboardPermissionFilter(signedInUser, search.RequiredPermission, "")
|
||||||
t.Logf("Searching for dashboards, SQL: %q\n", builder.GetSQLString())
|
t.Logf("Searching for dashboards, SQL: %q\n", builder.GetSQLString())
|
||||||
err = sqlStore.GetEngine().SQL(builder.GetSQLString(), builder.params...).Find(&res)
|
err = sqlStore.GetEngine().SQL(builder.GetSQLString(), builder.params...).Find(&res)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -167,7 +167,7 @@ func (ss *sqlStore) HandleAlertsQuery(ctx context.Context, query *alertmodels.Ge
|
|||||||
builder.Write(")")
|
builder.Write(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW)
|
builder.WriteDashboardPermissionFilter(query.User, dashboards.PERMISSION_VIEW, "")
|
||||||
|
|
||||||
builder.Write(" ORDER BY name ASC")
|
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(getFromLibraryElementDTOWithMeta(store.GetDialect()))
|
||||||
builder.Write(" INNER JOIN dashboard AS dashboard on le.folder_id = dashboard.id AND le.folder_id <> 0")
|
builder.Write(" INNER JOIN dashboard AS dashboard on le.folder_id = dashboard.id AND le.folder_id <> 0")
|
||||||
writeParamSelectorSQL(&builder, params...)
|
writeParamSelectorSQL(&builder, params...)
|
||||||
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW)
|
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW, "")
|
||||||
builder.Write(` OR dashboard.id=0`)
|
builder.Write(` OR dashboard.id=0`)
|
||||||
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryElements); err != nil {
|
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryElements); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -372,7 +372,7 @@ func (l *LibraryElementService) getAllLibraryElements(c context.Context, signedI
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if signedInUser.OrgRole != org.RoleAdmin {
|
if signedInUser.OrgRole != org.RoleAdmin {
|
||||||
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW)
|
builder.WriteDashboardPermissionFilter(signedInUser, dashboards.PERMISSION_VIEW, "")
|
||||||
}
|
}
|
||||||
if query.SortDirection == search.SortAlphaDesc.Name {
|
if query.SortDirection == search.SortAlphaDesc.Name {
|
||||||
builder.Write(" ORDER BY 1 DESC")
|
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(" INNER JOIN dashboard AS dashboard on lec.connection_id = dashboard.id")
|
||||||
builder.Write(` WHERE lec.element_id=?`, element.ID)
|
builder.Write(` WHERE lec.element_id=?`, element.ID)
|
||||||
if signedInUser.OrgRole != org.RoleAdmin {
|
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 {
|
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryElementConnections); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -90,7 +90,24 @@ func (api *Api) RegisterAPIEndpoints() {
|
|||||||
// ListPublicDashboards Gets list of public dashboards by orgId
|
// ListPublicDashboards Gets list of public dashboards by orgId
|
||||||
// GET /api/dashboards/public-dashboards
|
// GET /api/dashboards/public-dashboards
|
||||||
func (api *Api) ListPublicDashboards(c *contextmodel.ReqContext) response.Response {
|
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 {
|
if err != nil {
|
||||||
return response.Err(err)
|
return response.Err(err)
|
||||||
}
|
}
|
||||||
|
@ -89,19 +89,21 @@ func TestAPIFeatureFlag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIListPublicDashboard(t *testing.T) {
|
func TestAPIListPublicDashboard(t *testing.T) {
|
||||||
successResp := []PublicDashboardListResponse{
|
successResp := &PublicDashboardListResponseWithPagination{
|
||||||
|
PublicDashboards: []*PublicDashboardListResponse{
|
||||||
{
|
{
|
||||||
Uid: "1234asdfasdf",
|
Uid: "1234asdfasdf",
|
||||||
AccessToken: "asdfasdf",
|
AccessToken: "asdfasdf",
|
||||||
DashboardUid: "abc1234",
|
DashboardUid: "abc1234",
|
||||||
IsEnabled: true,
|
IsEnabled: true,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Name string
|
Name string
|
||||||
User *user.SignedInUser
|
User *user.SignedInUser
|
||||||
Response []PublicDashboardListResponse
|
Response *PublicDashboardListResponseWithPagination
|
||||||
ResponseErr error
|
ResponseErr error
|
||||||
ExpectedHttpResponse int
|
ExpectedHttpResponse int
|
||||||
}{
|
}{
|
||||||
@ -131,7 +133,7 @@ func TestAPIListPublicDashboard(t *testing.T) {
|
|||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
service := publicdashboards.NewFakePublicDashboardService(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()
|
Return(test.Response, test.ResponseErr).Maybe()
|
||||||
|
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
@ -143,10 +145,10 @@ func TestAPIListPublicDashboard(t *testing.T) {
|
|||||||
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
|
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
|
||||||
|
|
||||||
if test.ExpectedHttpResponse == http.StatusOK {
|
if test.ExpectedHttpResponse == http.StatusOK {
|
||||||
var jsonResp []PublicDashboardListResponse
|
var jsonResp PublicDashboardListResponseWithPagination
|
||||||
err := json.Unmarshal(response.Body.Bytes(), &jsonResp)
|
err := json.Unmarshal(response.Body.Bytes(), &jsonResp)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, jsonResp[0].Uid, "1234asdfasdf")
|
assert.Equal(t, jsonResp.PublicDashboards[0].Uid, "1234asdfasdf")
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.ResponseErr != nil {
|
if test.ResponseErr != nil {
|
||||||
@ -155,7 +157,7 @@ func TestAPIListPublicDashboard(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, "Internal server error", errResp.Message)
|
assert.Equal(t, "Internal server error", errResp.Message)
|
||||||
assert.Equal(t, "publicdashboards.internalServerError", errResp.MessageID)
|
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()
|
annotationsService := annotationstest.NewFakeAnnotationsRepo()
|
||||||
|
|
||||||
// create public dashboard
|
// create public dashboard
|
||||||
store := publicdashboardsStore.ProvideStore(db)
|
store := publicdashboardsStore.ProvideStore(db, db.Cfg, featuremgmt.WithFeatures())
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
ac := acmock.New()
|
ac := acmock.New()
|
||||||
ws := publicdashboardsService.ProvideServiceWrapper(store)
|
ws := publicdashboardsService.ProvideServiceWrapper(store)
|
||||||
|
@ -7,9 +7,13 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"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"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"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
|
// Define the storage implementation. We're generating the mock implementation
|
||||||
@ -17,6 +21,8 @@ import (
|
|||||||
type PublicDashboardStoreImpl struct {
|
type PublicDashboardStoreImpl struct {
|
||||||
sqlStore db.DB
|
sqlStore db.DB
|
||||||
log log.Logger
|
log log.Logger
|
||||||
|
cfg *setting.Cfg
|
||||||
|
features featuremgmt.FeatureToggles
|
||||||
}
|
}
|
||||||
|
|
||||||
var LogPrefix = "publicdashboards.store"
|
var LogPrefix = "publicdashboards.store"
|
||||||
@ -26,25 +32,54 @@ var LogPrefix = "publicdashboards.store"
|
|||||||
var _ publicdashboards.Store = (*PublicDashboardStoreImpl)(nil)
|
var _ publicdashboards.Store = (*PublicDashboardStoreImpl)(nil)
|
||||||
|
|
||||||
// Factory used by wire to dependency injection
|
// 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{
|
return &PublicDashboardStoreImpl{
|
||||||
sqlStore: sqlStore,
|
sqlStore: sqlStore,
|
||||||
log: log.New(LogPrefix),
|
log: log.New(LogPrefix),
|
||||||
|
cfg: cfg,
|
||||||
|
features: features,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAll Returns a list of public dashboards by orgId
|
// FindAllWithPagination Returns a list of public dashboards by orgId, based on permissions and with pagination
|
||||||
func (d *PublicDashboardStoreImpl) FindAll(ctx context.Context, orgId int64) ([]PublicDashboardListResponse, error) {
|
func (d *PublicDashboardStoreImpl) FindAllWithPagination(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error) {
|
||||||
resp := make([]PublicDashboardListResponse, 0)
|
resp := &PublicDashboardListResponseWithPagination{
|
||||||
|
PublicDashboards: make([]*PublicDashboardListResponse, 0),
|
||||||
|
TotalCount: 0,
|
||||||
|
}
|
||||||
|
|
||||||
err := d.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
|
recursiveQueriesAreSupported, err := d.sqlStore.RecursiveQueriesAreSupported()
|
||||||
sess.Table("dashboard_public").Select(
|
if err != nil {
|
||||||
"dashboard_public.uid, dashboard_public.access_token, dashboard.uid as dashboard_uid, dashboard_public.is_enabled, dashboard.title").
|
return nil, err
|
||||||
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")
|
|
||||||
|
|
||||||
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
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -2,18 +2,24 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
|
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"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/tag/tagimpl"
|
||||||
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -34,38 +40,122 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
|
|||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
sqlStore, cfg := db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
|
||||||
quotaService := quotatest.New(false, nil)
|
var sqlStore *sqlstore.SQLStore
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
var cfg *setting.Cfg
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := ProvideStore(sqlStore)
|
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
|
var orgId int64 = 1
|
||||||
|
|
||||||
bDash := insertTestDashboard(t, dashboardStore, "b", orgId, 0, true)
|
var publicdashboardStore *PublicDashboardStoreImpl
|
||||||
aDash := insertTestDashboard(t, dashboardStore, "a", orgId, 0, true)
|
|
||||||
cDash := insertTestDashboard(t, dashboardStore, "c", orgId, 0, true)
|
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())
|
||||||
|
|
||||||
|
bDash = insertTestDashboard(t, dashboardStore, "b", orgId, 0, false)
|
||||||
|
aDash = insertTestDashboard(t, dashboardStore, "a", orgId, 0, false)
|
||||||
|
cDash = insertTestDashboard(t, dashboardStore, "c", orgId, 0, false)
|
||||||
|
|
||||||
// these are in order of how they should be returned from ListPUblicDashboards
|
// these are in order of how they should be returned from ListPUblicDashboards
|
||||||
a := insertPublicDashboard(t, publicdashboardStore, aDash.UID, orgId, false, PublicShareType)
|
aPublicDash = insertPublicDashboard(t, publicdashboardStore, aDash.UID, orgId, false, PublicShareType)
|
||||||
b := insertPublicDashboard(t, publicdashboardStore, bDash.UID, orgId, true, PublicShareType)
|
bPublicDash = insertPublicDashboard(t, publicdashboardStore, bDash.UID, orgId, true, PublicShareType)
|
||||||
c := insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
|
cPublicDash = insertPublicDashboard(t, publicdashboardStore, cDash.UID, orgId, true, PublicShareType)
|
||||||
|
}
|
||||||
|
|
||||||
// this is case that can happen as of now, however, postgres and mysql sort
|
t.Run("FindAllWithPagination will return dashboard list based on orgId with pagination", func(t *testing.T) {
|
||||||
// null in the exact opposite fashion and there is no shared syntax to sort
|
setup()
|
||||||
// nulls in the same way in all 3 db's.
|
|
||||||
//d := insertPublicDashboard(t, publicdashboardStore, "missing", orgId, false)
|
|
||||||
|
|
||||||
// should not be included in response
|
// should not be included in response
|
||||||
_ = insertPublicDashboard(t, publicdashboardStore, "wrongOrgId", 777, false, PublicShareType)
|
_ = insertPublicDashboard(t, publicdashboardStore, "wrongOrgId", 777, false, PublicShareType)
|
||||||
|
|
||||||
resp, err := publicdashboardStore.FindAll(context.Background(), orgId)
|
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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, resp, 3)
|
query := &PublicDashboardListQuery{
|
||||||
assert.Equal(t, resp[0].Uid, a.Uid)
|
User: &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}},
|
||||||
assert.Equal(t, resp[1].Uid, b.Uid)
|
OrgID: orgId,
|
||||||
assert.Equal(t, resp[2].Uid, c.Uid)
|
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) {
|
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)
|
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dashboardStore = store
|
dashboardStore = store
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
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)
|
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dashboardStore = store
|
dashboardStore = store
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
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) {
|
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)
|
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dashboardStore = store
|
dashboardStore = store
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
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)
|
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dashboardStore = store
|
dashboardStore = store
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +409,7 @@ func TestIntegrationFindByAccessToken(t *testing.T) {
|
|||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
|
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
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)
|
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dashboardStore = store
|
dashboardStore = store
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, true)
|
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, true)
|
||||||
insertPublicDashboard(t, publicdashboardStore, savedDashboard2.UID, savedDashboard2.OrgID, false, PublicShareType)
|
insertPublicDashboard(t, publicdashboardStore, savedDashboard2.UID, savedDashboard2.OrgID, false, PublicShareType)
|
||||||
@ -468,7 +558,7 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
|
|||||||
quotaService := quotatest.New(false, nil)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
anotherSavedDashboard = insertTestDashboard(t, dashboardStore, "test another Dashie", 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)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
}
|
}
|
||||||
t.Run("GetOrgIdByAccessToken will OrgId when enabled", func(t *testing.T) {
|
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)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
|
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
savedPublicDashboard = insertPublicDashboard(t, publicdashboardStore, savedDashboard.UID, savedDashboard.OrgID, true, PublicShareType)
|
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) {
|
t.Run("returns nil when dashboard is not a folder", func(t *testing.T) {
|
||||||
sqlStore, _ := db.InitTestDBwithCfg(t)
|
sqlStore, _ := db.InitTestDBwithCfg(t)
|
||||||
dashboard := &dashboards.Dashboard{IsFolder: false}
|
dashboard := &dashboards.Dashboard{IsFolder: false}
|
||||||
store := ProvideStore(sqlStore)
|
store := ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||||
pubdashes, err := store.FindByDashboardFolder(context.Background(), dashboard)
|
pubdashes, err := store.FindByDashboardFolder(context.Background(), dashboard)
|
||||||
|
|
||||||
require.NoError(t, err)
|
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) {
|
t.Run("returns nil when dashboard is nil", func(t *testing.T) {
|
||||||
sqlStore, _ := db.InitTestDBwithCfg(t)
|
sqlStore, _ := db.InitTestDBwithCfg(t)
|
||||||
store := ProvideStore(sqlStore)
|
store := ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||||
pubdashes, err := store.FindByDashboardFolder(context.Background(), nil)
|
pubdashes, err := store.FindByDashboardFolder(context.Background(), nil)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -696,7 +786,7 @@ func TestGetDashboardByFolder(t *testing.T) {
|
|||||||
quotaService := quotatest.New(false, nil)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pubdashStore := ProvideStore(sqlStore)
|
pubdashStore := ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "title", 1, 1, true, PublicShareType)
|
dashboard := insertTestDashboard(t, dashboardStore, "title", 1, 1, true, PublicShareType)
|
||||||
pubdash := insertPublicDashboard(t, pubdashStore, dashboard.UID, dashboard.OrgID, true, PublicShareType)
|
pubdash := insertPublicDashboard(t, pubdashStore, dashboard.UID, dashboard.OrgID, true, PublicShareType)
|
||||||
dashboard2 := insertTestDashboard(t, dashboardStore, "title", 1, 2, 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)
|
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dashboardStore = store
|
dashboardStore = store
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore, cfg, featuremgmt.WithFeatures())
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, false)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, false)
|
||||||
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, false)
|
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, false)
|
||||||
savedDashboard3 = insertTestDashboard(t, dashboardStore, "testDashie3", 2, 0, false)
|
savedDashboard3 = insertTestDashboard(t, dashboardStore, "testDashie3", 2, 0, false)
|
||||||
@ -827,3 +917,50 @@ func insertPublicDashboard(t *testing.T, publicdashboardStore *PublicDashboardSt
|
|||||||
|
|
||||||
return pubdash
|
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"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/dashboard"
|
"github.com/grafana/grafana/pkg/kinds/dashboard"
|
||||||
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublicDashboardErr represents a dashboard error.
|
// PublicDashboardErr represents a dashboard error.
|
||||||
@ -103,6 +104,22 @@ func (pd PublicDashboard) TableName() string {
|
|||||||
return "dashboard_public"
|
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 {
|
type PublicDashboardListResponse struct {
|
||||||
Uid string `json:"uid" xorm:"uid"`
|
Uid string `json:"uid" xorm:"uid"`
|
||||||
AccessToken string `json:"accessToken" xorm:"access_token"`
|
AccessToken string `json:"accessToken" xorm:"access_token"`
|
||||||
|
@ -139,22 +139,22 @@ func (_m *FakePublicDashboardService) Find(ctx context.Context, uid string) (*mo
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAll provides a mock function with given fields: ctx, u, orgId
|
// FindAllWithPagination provides a mock function with given fields: ctx, query
|
||||||
func (_m *FakePublicDashboardService) FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]models.PublicDashboardListResponse, error) {
|
func (_m *FakePublicDashboardService) FindAllWithPagination(ctx context.Context, query *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error) {
|
||||||
ret := _m.Called(ctx, u, orgId)
|
ret := _m.Called(ctx, query)
|
||||||
|
|
||||||
var r0 []models.PublicDashboardListResponse
|
var r0 *models.PublicDashboardListResponseWithPagination
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, int64) []models.PublicDashboardListResponse); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *models.PublicDashboardListQuery) *models.PublicDashboardListResponseWithPagination); ok {
|
||||||
r0 = rf(ctx, u, orgId)
|
r0 = rf(ctx, query)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).([]models.PublicDashboardListResponse)
|
r0 = ret.Get(0).(*models.PublicDashboardListResponseWithPagination)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, *user.SignedInUser, int64) error); ok {
|
if rf, ok := ret.Get(1).(func(context.Context, *models.PublicDashboardListQuery) error); ok {
|
||||||
r1 = rf(ctx, u, orgId)
|
r1 = rf(ctx, query)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
}
|
}
|
||||||
|
@ -123,22 +123,22 @@ func (_m *FakePublicDashboardStore) Find(ctx context.Context, uid string) (*mode
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAll provides a mock function with given fields: ctx, orgId
|
// FindAllWithPagination provides a mock function with given fields: ctx, query
|
||||||
func (_m *FakePublicDashboardStore) FindAll(ctx context.Context, orgId int64) ([]models.PublicDashboardListResponse, error) {
|
func (_m *FakePublicDashboardStore) FindAllWithPagination(ctx context.Context, query *models.PublicDashboardListQuery) (*models.PublicDashboardListResponseWithPagination, error) {
|
||||||
ret := _m.Called(ctx, orgId)
|
ret := _m.Called(ctx, query)
|
||||||
|
|
||||||
var r0 []models.PublicDashboardListResponse
|
var r0 *models.PublicDashboardListResponseWithPagination
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, int64) []models.PublicDashboardListResponse); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *models.PublicDashboardListQuery) *models.PublicDashboardListResponseWithPagination); ok {
|
||||||
r0 = rf(ctx, orgId)
|
r0 = rf(ctx, query)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).([]models.PublicDashboardListResponse)
|
r0 = ret.Get(0).(*models.PublicDashboardListResponseWithPagination)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
|
if rf, ok := ret.Get(1).(func(context.Context, *models.PublicDashboardListQuery) error); ok {
|
||||||
r1 = rf(ctx, orgId)
|
r1 = rf(ctx, query)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ type Service interface {
|
|||||||
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||||
FindAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error)
|
FindAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error)
|
||||||
FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, 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)
|
Find(ctx context.Context, uid string) (*PublicDashboard, error)
|
||||||
Create(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
Create(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
||||||
Update(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)
|
FindByAccessToken(ctx context.Context, accessToken string) (*PublicDashboard, error)
|
||||||
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||||
FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, 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)
|
Create(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
|
||||||
Update(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
|
Update(ctx context.Context, cmd SavePublicDashboardCommand) (int64, error)
|
||||||
Delete(ctx context.Context, uid string) (int64, error)
|
Delete(ctx context.Context, uid string) (int64, error)
|
||||||
|
@ -663,7 +663,7 @@ func TestGetQueryDataResponse(t *testing.T) {
|
|||||||
sqlStore := sqlstore.InitTestDB(t)
|
sqlStore := sqlstore.InitTestDB(t)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
fakeQueryService := &query.FakeQueryService{}
|
fakeQueryService := &query.FakeQueryService{}
|
||||||
fakeQueryService.On("QueryData", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&backend.QueryDataResponse{}, nil)
|
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)
|
sqlStore := db.InitTestDB(t)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
||||||
require.NoError(t, err)
|
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)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
publicDashboard := &PublicDashboard{
|
publicDashboard := &PublicDashboard{
|
||||||
Uid: "1",
|
Uid: "1",
|
||||||
@ -1194,7 +1194,7 @@ func TestBuildMetricRequest(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
nonPublicDashboard := insertTestDashboard(t, dashboardStore, "testNonPublicDashie", 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")
|
return "", ErrInternalServerError.Errorf("failed to generate a unique accessToken for public dashboard")
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAll Returns a list of public dashboards by orgId
|
// FindAllWithPagination Returns a list of public dashboards by orgId, based on permissions and with pagination
|
||||||
func (pd *PublicDashboardServiceImpl) FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]PublicDashboardListResponse, error) {
|
func (pd *PublicDashboardServiceImpl) FindAllWithPagination(ctx context.Context, query *PublicDashboardListQuery) (*PublicDashboardListResponseWithPagination, error) {
|
||||||
publicDashboards, err := pd.store.FindAll(ctx, orgId)
|
query.Offset = query.Limit * (query.Page - 1)
|
||||||
|
resp, err := pd.store.FindAllWithPagination(ctx, query)
|
||||||
if err != nil {
|
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) {
|
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
|
// Checks to see if PublicDashboard.ExistsEnabledByDashboardUid is true on create or changed on update
|
||||||
func publicDashboardIsEnabledChanged(existingPubdash *PublicDashboard, newPubdash *PublicDashboard) bool {
|
func publicDashboardIsEnabledChanged(existingPubdash *PublicDashboard, newPubdash *PublicDashboard) bool {
|
||||||
// creating dashboard, enabled true
|
// creating dashboard, enabled true
|
||||||
|
@ -195,7 +195,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
quotaService := quotatest.New(false, nil)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||||
require.NoError(t, err)
|
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)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
quotaService := quotatest.New(false, nil)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||||
require.NoError(t, err)
|
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)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
|
|
||||||
@ -325,7 +325,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
quotaService := quotatest.New(false, nil)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||||
require.NoError(t, err)
|
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)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
|
|
||||||
@ -359,7 +359,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
quotaService := quotatest.New(false, nil)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||||
templateVars := make([]map[string]interface{}, 1)
|
templateVars := make([]map[string]interface{}, 1)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, templateVars, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, templateVars, nil)
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
@ -474,7 +474,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
quotaService := quotatest.New(false, nil)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||||
require.NoError(t, err)
|
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)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
|
|
||||||
@ -519,7 +519,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
|||||||
quotaService := quotatest.New(false, nil)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
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)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
|
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
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)
|
quotaService := quotatest.New(false, nil)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
|
||||||
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
|
|
||||||
@ -915,186 +915,102 @@ func TestDashboardEnabledChanged(t *testing.T) {
|
|||||||
func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
u *user.SignedInUser
|
query *PublicDashboardListQuery
|
||||||
orgId int64
|
}
|
||||||
|
|
||||||
|
type mockResponse struct {
|
||||||
|
PublicDashboardListResponseWithPagination *PublicDashboardListResponseWithPagination
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
mockedDashboards := []*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,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
evaluateFunc func(c context.Context, u *user.SignedInUser, e accesscontrol.Evaluator) (bool, error)
|
want *PublicDashboardListResponseWithPagination
|
||||||
want []PublicDashboardListResponse
|
mockResponse *mockResponse
|
||||||
wantErr assert.ErrorAssertionFunc
|
wantErr assert.ErrorAssertionFunc
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "should return empty list when user does not have permissions to read any dashboard",
|
name: "should return correct pagination response",
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
u: &user.SignedInUser{OrgID: 1},
|
query: &PublicDashboardListQuery{
|
||||||
orgId: 1,
|
User: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||||
},
|
|
||||||
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"}}},
|
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
||||||
},
|
},
|
||||||
orgId: 1,
|
OrgID: 1,
|
||||||
|
Page: 1,
|
||||||
|
Limit: 50,
|
||||||
},
|
},
|
||||||
want: []PublicDashboardListResponse{
|
|
||||||
{
|
|
||||||
Uid: "0GwW7mgVk",
|
|
||||||
AccessToken: "0b458cb7fe7f42c68712078bcacee6e3",
|
|
||||||
DashboardUid: "0S6TmO67z",
|
|
||||||
Title: "my zero dashboard",
|
|
||||||
IsEnabled: true,
|
|
||||||
},
|
},
|
||||||
|
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,
|
wantErr: assert.NoError,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should return orphaned public dashboards",
|
name: "should return error when store returns error",
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
u: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
query: &PublicDashboardListQuery{
|
||||||
|
User: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||||
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}},
|
||||||
},
|
},
|
||||||
orgId: 1,
|
OrgID: 1,
|
||||||
},
|
Page: 1,
|
||||||
evaluateFunc: func(c context.Context, u *user.SignedInUser, e accesscontrol.Evaluator) (bool, error) {
|
Limit: 50,
|
||||||
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,
|
mockResponse: &mockResponse{
|
||||||
},
|
PublicDashboardListResponseWithPagination: nil,
|
||||||
{
|
Err: errors.New("an err"),
|
||||||
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,
|
want: nil,
|
||||||
wantErr: assert.Error,
|
wantErr: assert.Error,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
mockedDashboards := []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,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
store := NewFakePublicDashboardStore(t)
|
|
||||||
store.On("FindAll", mock.Anything, mock.Anything).
|
|
||||||
Return(mockedDashboards, nil)
|
|
||||||
|
|
||||||
ac := tests.SetupMockAccesscontrol(t,
|
ac := tests.SetupMockAccesscontrol(t,
|
||||||
func(c context.Context, siu *user.SignedInUser, _ accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
func(c context.Context, siu *user.SignedInUser, _ accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
||||||
return []accesscontrol.Permission{}, nil
|
return []accesscontrol.Permission{}, nil
|
||||||
@ -1102,21 +1018,23 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for _, tt := range testCases {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
store := NewFakePublicDashboardStore(t)
|
||||||
|
store.On("FindAllWithPagination", mock.Anything, mock.Anything).
|
||||||
|
Return(tt.mockResponse.PublicDashboardListResponseWithPagination, tt.mockResponse.Err)
|
||||||
|
|
||||||
pd := &PublicDashboardServiceImpl{
|
pd := &PublicDashboardServiceImpl{
|
||||||
log: log.New("test.logger"),
|
log: log.New("test.logger"),
|
||||||
store: store,
|
store: store,
|
||||||
ac: ac,
|
ac: ac,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range testCases {
|
got, err := pd.FindAllWithPagination(tt.args.ctx, tt.args.query)
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
if !tt.wantErr(t, err, fmt.Sprintf("FindAllWithPagination(%v, %v)", tt.args.ctx, tt.args.query)) {
|
||||||
ac.EvaluateFunc = tt.evaluateFunc
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
return
|
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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,10 @@ import {
|
|||||||
SessionUser,
|
SessionUser,
|
||||||
} from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
|
} from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
|
||||||
import { DashboardModel } from 'app/features/dashboard/state';
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
import { ListPublicDashboardResponse } from 'app/features/manage-dashboards/types';
|
import {
|
||||||
|
PublicDashboardListWithPagination,
|
||||||
|
PublicDashboardListWithPaginationResponse,
|
||||||
|
} from 'app/features/manage-dashboards/types';
|
||||||
|
|
||||||
type ReqOptions = {
|
type ReqOptions = {
|
||||||
manageError?: (err: unknown) => { error: unknown };
|
manageError?: (err: unknown) => { error: unknown };
|
||||||
@ -137,9 +140,13 @@ export const publicDashboardApi = createApi({
|
|||||||
}),
|
}),
|
||||||
providesTags: (result, _, email) => [{ type: 'ActiveUserDashboards', id: email }],
|
providesTags: (result, _, email) => [{ type: 'ActiveUserDashboards', id: email }],
|
||||||
}),
|
}),
|
||||||
listPublicDashboards: builder.query<ListPublicDashboardResponse[], void>({
|
listPublicDashboards: builder.query<PublicDashboardListWithPagination, number | void>({
|
||||||
query: () => ({
|
query: (page = 1) => ({
|
||||||
url: '/dashboards/public-dashboards',
|
url: `/dashboards/public-dashboards?page=${page}&perpage=8`,
|
||||||
|
}),
|
||||||
|
transformResponse: (response: PublicDashboardListWithPaginationResponse) => ({
|
||||||
|
...response,
|
||||||
|
totalPages: Math.ceil(response.totalCount / response.perPage),
|
||||||
}),
|
}),
|
||||||
providesTags: ['AuditTablePublicDashboard'],
|
providesTags: ['AuditTablePublicDashboard'],
|
||||||
}),
|
}),
|
||||||
|
@ -11,11 +11,11 @@ import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
|||||||
import { backendSrv } from 'app/core/services/backend_srv';
|
import { backendSrv } from 'app/core/services/backend_srv';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
|
|
||||||
import { ListPublicDashboardResponse } from '../../types';
|
import { PublicDashboardListResponse, PublicDashboardListWithPaginationResponse } from '../../types';
|
||||||
|
|
||||||
import { PublicDashboardListTable } from './PublicDashboardListTable';
|
import { PublicDashboardListTable } from './PublicDashboardListTable';
|
||||||
|
|
||||||
const publicDashboardListResponse: ListPublicDashboardResponse[] = [
|
const publicDashboardListResponse: PublicDashboardListResponse[] = [
|
||||||
{
|
{
|
||||||
uid: 'SdZwuCZVz',
|
uid: 'SdZwuCZVz',
|
||||||
accessToken: 'beeaf92f6ab3467f80b2be922c7741ab',
|
accessToken: 'beeaf92f6ab3467f80b2be922c7741ab',
|
||||||
@ -32,7 +32,7 @@ const publicDashboardListResponse: ListPublicDashboardResponse[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const orphanedDashboardListResponse: ListPublicDashboardResponse[] = [
|
const orphanedDashboardListResponse: PublicDashboardListResponse[] = [
|
||||||
{
|
{
|
||||||
uid: 'SdZwuCZVz2',
|
uid: 'SdZwuCZVz2',
|
||||||
accessToken: 'beeaf92f6ab3467f80b2be922c7741ab',
|
accessToken: 'beeaf92f6ab3467f80b2be922c7741ab',
|
||||||
@ -49,9 +49,15 @@ const orphanedDashboardListResponse: ListPublicDashboardResponse[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const paginationResponse: Omit<PublicDashboardListWithPaginationResponse, 'publicDashboards'> = {
|
||||||
|
page: 1,
|
||||||
|
perPage: 50,
|
||||||
|
totalCount: 50,
|
||||||
|
};
|
||||||
|
|
||||||
const server = setupServer(
|
const server = setupServer(
|
||||||
rest.get('/api/dashboards/public-dashboards', (_, res, ctx) =>
|
rest.get('/api/dashboards/public-dashboards', (_, res, ctx) =>
|
||||||
res(ctx.status(200), ctx.json(publicDashboardListResponse))
|
res(ctx.status(200), ctx.json({ ...paginationResponse, publicDashboards: publicDashboardListResponse }))
|
||||||
),
|
),
|
||||||
rest.delete('/api/dashboards/uid/:dashboardUid/public-dashboards/:uid', (_, res, ctx) => res(ctx.status(200)))
|
rest.delete('/api/dashboards/uid/:dashboardUid/public-dashboards/:uid', (_, res, ctx) => res(ctx.status(200)))
|
||||||
);
|
);
|
||||||
@ -104,9 +110,16 @@ describe('Show table', () => {
|
|||||||
expect(screen.getAllByRole('listitem')).toHaveLength(publicDashboardListResponse.length);
|
expect(screen.getAllByRole('listitem')).toHaveLength(publicDashboardListResponse.length);
|
||||||
});
|
});
|
||||||
it('renders empty list', async () => {
|
it('renders empty list', async () => {
|
||||||
|
const emptyListRS: PublicDashboardListWithPaginationResponse = {
|
||||||
|
publicDashboards: [],
|
||||||
|
totalCount: 0,
|
||||||
|
page: 1,
|
||||||
|
perPage: 50,
|
||||||
|
};
|
||||||
|
|
||||||
server.use(
|
server.use(
|
||||||
rest.get('/api/dashboards/public-dashboards', (req, res, ctx) => {
|
rest.get('/api/dashboards/public-dashboards', (req, res, ctx) => {
|
||||||
return res(ctx.status(200), ctx.json([]));
|
return res(ctx.status(200), ctx.json(emptyListRS));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -149,7 +162,10 @@ describe('Delete public dashboard', () => {
|
|||||||
|
|
||||||
describe('Orphaned public dashboard', () => {
|
describe('Orphaned public dashboard', () => {
|
||||||
it('renders orphaned and non orphaned public dashboards items correctly', async () => {
|
it('renders orphaned and non orphaned public dashboards items correctly', async () => {
|
||||||
const response = [...publicDashboardListResponse, ...orphanedDashboardListResponse];
|
const response: PublicDashboardListWithPaginationResponse = {
|
||||||
|
...paginationResponse,
|
||||||
|
publicDashboards: [...publicDashboardListResponse, ...orphanedDashboardListResponse],
|
||||||
|
};
|
||||||
server.use(
|
server.use(
|
||||||
rest.get('/api/dashboards/public-dashboards', (req, res, ctx) => {
|
rest.get('/api/dashboards/public-dashboards', (req, res, ctx) => {
|
||||||
return res(ctx.status(200), ctx.json(response));
|
return res(ctx.status(200), ctx.json(response));
|
||||||
@ -158,13 +174,13 @@ describe('Orphaned public dashboard', () => {
|
|||||||
jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true);
|
jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true);
|
||||||
|
|
||||||
await renderPublicDashboardTable(true);
|
await renderPublicDashboardTable(true);
|
||||||
response.forEach((pd, idx) => {
|
response.publicDashboards.forEach((pd, idx) => {
|
||||||
renderPublicDashboardItemCorrectly(pd, idx, true);
|
renderPublicDashboardItemCorrectly(pd, idx, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderPublicDashboardItemCorrectly = (pd: ListPublicDashboardResponse, idx: number, hasWriteAccess: boolean) => {
|
const renderPublicDashboardItemCorrectly = (pd: PublicDashboardListResponse, idx: number, hasWriteAccess: boolean) => {
|
||||||
const isOrphaned = !pd.dashboardUid;
|
const isOrphaned = !pd.dashboardUid;
|
||||||
|
|
||||||
const cardItems = screen.getAllByRole('listitem');
|
const cardItems = screen.getAllByRole('listitem');
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { useMedia } from 'react-use';
|
import { useMedia } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data/src';
|
import { GrafanaTheme2 } from '@grafana/data/src';
|
||||||
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import { LinkButton, useStyles2, Spinner, Card, useTheme2, Tooltip, Icon, Switch } from '@grafana/ui/src';
|
import {
|
||||||
|
LinkButton,
|
||||||
|
useStyles2,
|
||||||
|
Spinner,
|
||||||
|
Card,
|
||||||
|
useTheme2,
|
||||||
|
Tooltip,
|
||||||
|
Icon,
|
||||||
|
Switch,
|
||||||
|
Pagination,
|
||||||
|
HorizontalGroup,
|
||||||
|
} from '@grafana/ui/src';
|
||||||
import { Page } from 'app/core/components/Page/Page';
|
import { Page } from 'app/core/components/Page/Page';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import {
|
import {
|
||||||
@ -19,11 +30,11 @@ import {
|
|||||||
import { isOrgAdmin } from 'app/features/plugins/admin/permissions';
|
import { isOrgAdmin } from 'app/features/plugins/admin/permissions';
|
||||||
import { AccessControlAction } from 'app/types';
|
import { AccessControlAction } from 'app/types';
|
||||||
|
|
||||||
import { ListPublicDashboardResponse } from '../../types';
|
import { PublicDashboardListResponse } from '../../types';
|
||||||
|
|
||||||
import { DeletePublicDashboardButton } from './DeletePublicDashboardButton';
|
import { DeletePublicDashboardButton } from './DeletePublicDashboardButton';
|
||||||
|
|
||||||
const PublicDashboardCard = ({ pd }: { pd: ListPublicDashboardResponse }) => {
|
const PublicDashboardCard = ({ pd }: { pd: PublicDashboardListResponse }) => {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const isMobile = useMedia(`(max-width: ${theme.breakpoints.values.sm}px)`);
|
const isMobile = useMedia(`(max-width: ${theme.breakpoints.values.sm}px)`);
|
||||||
@ -34,7 +45,7 @@ const PublicDashboardCard = ({ pd }: { pd: ListPublicDashboardResponse }) => {
|
|||||||
const hasWritePermissions = contextSrv.hasAccess(AccessControlAction.DashboardsPublicWrite, isOrgAdmin());
|
const hasWritePermissions = contextSrv.hasAccess(AccessControlAction.DashboardsPublicWrite, isOrgAdmin());
|
||||||
const isOrphaned = !pd.dashboardUid;
|
const isOrphaned = !pd.dashboardUid;
|
||||||
|
|
||||||
const onTogglePause = (pd: ListPublicDashboardResponse, isPaused: boolean) => {
|
const onTogglePause = (pd: PublicDashboardListResponse, isPaused: boolean) => {
|
||||||
const req = {
|
const req = {
|
||||||
dashboard: { uid: pd.dashboardUid },
|
dashboard: { uid: pd.dashboardUid },
|
||||||
payload: {
|
payload: {
|
||||||
@ -118,20 +129,33 @@ const PublicDashboardCard = ({ pd }: { pd: ListPublicDashboardResponse }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const PublicDashboardListTable = () => {
|
export const PublicDashboardListTable = () => {
|
||||||
const styles = useStyles2(getStyles);
|
const [page, setPage] = useState(1);
|
||||||
|
|
||||||
const { data: publicDashboards, isLoading, isFetching } = useListPublicDashboardsQuery();
|
const styles = useStyles2(getStyles);
|
||||||
|
const { data: paginatedPublicDashboards, isLoading, isFetching, isError } = useListPublicDashboardsQuery(page);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page navId="dashboards/public" actions={isFetching && <Spinner />}>
|
<Page navId="dashboards/public" actions={isFetching && <Spinner />}>
|
||||||
<Page.Contents isLoading={isLoading}>
|
<Page.Contents isLoading={isLoading}>
|
||||||
|
{!isLoading && !isError && !!paginatedPublicDashboards && (
|
||||||
|
<div>
|
||||||
<ul className={styles.list}>
|
<ul className={styles.list}>
|
||||||
{publicDashboards?.map((pd: ListPublicDashboardResponse) => (
|
{paginatedPublicDashboards.publicDashboards.map((pd: PublicDashboardListResponse) => (
|
||||||
<li key={pd.uid}>
|
<li key={pd.uid}>
|
||||||
<PublicDashboardCard pd={pd} />
|
<PublicDashboardCard pd={pd} />
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
<HorizontalGroup justify="flex-end">
|
||||||
|
<Pagination
|
||||||
|
onNavigate={setPage}
|
||||||
|
currentPage={paginatedPublicDashboards.page}
|
||||||
|
numberOfPages={paginatedPublicDashboards.totalPages}
|
||||||
|
hideWhenSinglePage
|
||||||
|
/>
|
||||||
|
</HorizontalGroup>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Page.Contents>
|
</Page.Contents>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
@ -140,6 +164,7 @@ export const PublicDashboardListTable = () => {
|
|||||||
const getStyles = (theme: GrafanaTheme2) => ({
|
const getStyles = (theme: GrafanaTheme2) => ({
|
||||||
list: css`
|
list: css`
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
margin-bottom: ${theme.spacing(2)};
|
||||||
`,
|
`,
|
||||||
card: css`
|
card: css`
|
||||||
${theme.breakpoints.up('sm')} {
|
${theme.breakpoints.up('sm')} {
|
||||||
|
@ -18,10 +18,21 @@ export type DeleteDashboardResponse = {
|
|||||||
title: string;
|
title: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ListPublicDashboardResponse {
|
export interface PublicDashboardListWithPaginationResponse {
|
||||||
|
publicDashboards: PublicDashboardListResponse[];
|
||||||
|
page: number;
|
||||||
|
perPage: number;
|
||||||
|
totalCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PublicDashboardListResponse {
|
||||||
uid: string;
|
uid: string;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
dashboardUid: string;
|
dashboardUid: string;
|
||||||
title: string;
|
title: string;
|
||||||
isEnabled: boolean;
|
isEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PublicDashboardListWithPagination extends PublicDashboardListWithPaginationResponse {
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user