Public Dashboards: Usage Insights (#52768)

This commit is contained in:
owensmallwood
2022-08-10 14:14:48 -03:00
committed by GitHub
parent 5e4d5eb14b
commit dc23643bee
15 changed files with 217 additions and 0 deletions
+6
View File
@@ -79,6 +79,11 @@ func (api *Api) GetPublicDashboard(c *models.ReqContext) response.Response {
return handleDashboardErr(http.StatusInternalServerError, "Failed to get public dashboard", err)
}
pubDash, err := api.PublicDashboardService.GetPublicDashboardConfig(c.Req.Context(), dash.OrgId, dash.Uid)
if err != nil {
return handleDashboardErr(http.StatusInternalServerError, "Failed to get public dashboard config", err)
}
meta := dtos.DashboardMeta{
Slug: dash.Slug,
Type: models.DashTypeDB,
@@ -93,6 +98,7 @@ func (api *Api) GetPublicDashboard(c *models.ReqContext) response.Response {
IsFolder: false,
FolderId: dash.FolderId,
PublicDashboardAccessToken: accessToken,
PublicDashboardUID: pubDash.Uid,
}
dto := dtos.DashboardFullWithMeta{Meta: meta, Dashboard: dash.Data}
@@ -43,6 +43,8 @@ func TestAPIGetPublicDashboard(t *testing.T) {
service := publicdashboards.NewFakePublicDashboardService(t)
service.On("GetPublicDashboard", mock.Anything, mock.AnythingOfType("string")).
Return(&models.Dashboard{}, nil).Maybe()
service.On("GetPublicDashboardConfig", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).
Return(&PublicDashboard{}, nil).Maybe()
testServer := setupTestServer(t, cfg, qs, featuremgmt.WithFeatures(), service, nil)
@@ -95,6 +97,8 @@ func TestAPIGetPublicDashboard(t *testing.T) {
service := publicdashboards.NewFakePublicDashboardService(t)
service.On("GetPublicDashboard", mock.Anything, mock.AnythingOfType("string")).
Return(test.PublicDashboardResult, test.PublicDashboardErr).Maybe()
service.On("GetPublicDashboardConfig", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).
Return(&PublicDashboard{}, nil).Maybe()
testServer := setupTestServer(
t,
@@ -1,8 +1,12 @@
package api
import (
"net/http"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/web"
)
func SetPublicDashboardFlag() func(c *models.ReqContext) {
@@ -11,6 +15,31 @@ func SetPublicDashboardFlag() func(c *models.ReqContext) {
}
}
func RequiresValidAccessToken(publicDashboardService publicdashboards.Service) func(c *models.ReqContext) {
return func(c *models.ReqContext) {
accessToken, ok := web.Params(c.Req)[":accessToken"]
// Check access token is present on the request
if !ok || accessToken == "" {
c.JsonApiErr(http.StatusBadRequest, "Invalid access token", nil)
return
}
// Check that the access token references an enabled public dashboard
exists, err := publicDashboardService.AccessTokenExists(c.Req.Context(), accessToken)
if err != nil {
c.JsonApiErr(http.StatusInternalServerError, "Error validating access token", nil)
return
}
if !exists {
c.JsonApiErr(http.StatusBadRequest, "Invalid access token", nil)
return
}
}
}
func CountPublicDashboardRequest() func(c *models.ReqContext) {
return func(c *models.ReqContext) {
metrics.MPublicDashboardRequestCount.Inc()
@@ -0,0 +1,75 @@
package api
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
"github.com/grafana/grafana/pkg/services/publicdashboards"
publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestRequiresValidAccessToken(t *testing.T) {
t.Run("Returns 404 when access token is empty", func(t *testing.T) {
request, err := http.NewRequest("GET", "/api/public/ma/events/", nil)
require.NoError(t, err)
resp := runMiddleware(request, mockAccessTokenExistsResponse(false, nil))
require.Equal(t, http.StatusNotFound, resp.Code)
})
t.Run("Returns 200 when public dashboard with access token exists", func(t *testing.T) {
request, err := http.NewRequest("GET", "/api/public/ma/events/myAccessToken", nil)
require.NoError(t, err)
resp := runMiddleware(request, mockAccessTokenExistsResponse(true, nil))
require.Equal(t, http.StatusOK, resp.Code)
})
t.Run("Returns 400 when public dashboard with access token does not exist", func(t *testing.T) {
request, err := http.NewRequest("GET", "/api/public/ma/events/myAccessToken", nil)
require.NoError(t, err)
resp := runMiddleware(request, mockAccessTokenExistsResponse(false, nil))
require.Equal(t, http.StatusBadRequest, resp.Code)
})
t.Run("Returns 500 when public dashboard service gives an error", func(t *testing.T) {
request, err := http.NewRequest("GET", "/api/public/ma/events/myAccessToken", nil)
require.NoError(t, err)
resp := runMiddleware(request, mockAccessTokenExistsResponse(false, fmt.Errorf("error not found")))
require.Equal(t, http.StatusInternalServerError, resp.Code)
})
}
func mockAccessTokenExistsResponse(returnArguments ...interface{}) *publicdashboardsService.PublicDashboardServiceImpl {
fakeStore := &publicdashboards.FakePublicDashboardStore{}
fakeStore.On("AccessTokenExists", mock.Anything, mock.Anything).Return(returnArguments[0], returnArguments[1])
return publicdashboardsService.ProvideService(setting.NewCfg(), fakeStore)
}
func runMiddleware(request *http.Request, pubdashService *publicdashboardsService.PublicDashboardServiceImpl) *httptest.ResponseRecorder {
recorder := httptest.NewRecorder()
m := web.New()
initCtx := &models.ReqContext{}
m.Use(func(c *web.Context) {
initCtx.Context = c
c.Req = c.Req.WithContext(ctxkey.Set(c.Req.Context(), initCtx))
})
m.Get("/api/public/ma/events/:accessToken", RequiresValidAccessToken(pubdashService))
m.ServeHTTP(recorder, request)
return recorder
}