mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
public dashboards: rename api functions (#57789)
This PR imposes better naming conventions on public dashboards api * rename api functions and remove use of _config_ noun * fix tests Co-authored-by: Ezequiel Victorero <ezequiel.victorero@grafana.com>
This commit is contained in:
parent
6b7d6fe0cb
commit
bf672f960a
@ -245,7 +245,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
|
||||
setup()
|
||||
|
||||
uid := util.GenerateShortUID()
|
||||
cmd := publicDashboardModels.SavePublicDashboardConfigCommand{
|
||||
cmd := publicDashboardModels.SavePublicDashboardCommand{
|
||||
PublicDashboard: publicDashboardModels.PublicDashboard{
|
||||
Uid: uid,
|
||||
DashboardUid: savedDash.Uid,
|
||||
@ -280,7 +280,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
|
||||
setup()
|
||||
|
||||
uid := util.GenerateShortUID()
|
||||
cmd := publicDashboardModels.SavePublicDashboardConfigCommand{
|
||||
cmd := publicDashboardModels.SavePublicDashboardCommand{
|
||||
PublicDashboard: publicDashboardModels.PublicDashboard{
|
||||
Uid: uid,
|
||||
DashboardUid: savedDash.Uid,
|
||||
|
@ -4,10 +4,8 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
@ -17,7 +15,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
@ -60,7 +57,7 @@ func (api *Api) RegisterAPIEndpoints() {
|
||||
// because it is deeply dependent on the HTTPServer.Index() method and would result in a
|
||||
// circular dependency
|
||||
|
||||
api.RouteRegister.Get("/api/public/dashboards/:accessToken", routing.Wrap(api.GetPublicDashboard))
|
||||
api.RouteRegister.Get("/api/public/dashboards/:accessToken", routing.Wrap(api.ViewPublicDashboard))
|
||||
api.RouteRegister.Post("/api/public/dashboards/:accessToken/panels/:panelId/query", routing.Wrap(api.QueryPublicDashboard))
|
||||
api.RouteRegister.Get("/api/public/dashboards/:accessToken/annotations", routing.Wrap(api.GetAnnotations))
|
||||
|
||||
@ -74,51 +71,12 @@ func (api *Api) RegisterAPIEndpoints() {
|
||||
// Get public dashboard
|
||||
api.RouteRegister.Get("/api/dashboards/uid/:dashboardUid/public-dashboards",
|
||||
auth(middleware.ReqSignedIn, accesscontrol.EvalPermission(dashboards.ActionDashboardsRead, uidScope)),
|
||||
routing.Wrap(api.GetPublicDashboardConfig))
|
||||
routing.Wrap(api.GetPublicDashboard))
|
||||
|
||||
// Create/Update Public Dashboard
|
||||
api.RouteRegister.Post("/api/dashboards/uid/:dashboardUid/public-dashboards",
|
||||
auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(dashboards.ActionDashboardsPublicWrite, uidScope)),
|
||||
routing.Wrap(api.SavePublicDashboardConfig))
|
||||
}
|
||||
|
||||
// GetPublicDashboard Gets public dashboard
|
||||
// GET /api/public/dashboards/:accessToken
|
||||
func (api *Api) GetPublicDashboard(c *models.ReqContext) response.Response {
|
||||
accessToken := web.Params(c.Req)[":accessToken"]
|
||||
|
||||
if !tokens.IsValidAccessToken(accessToken) {
|
||||
return response.Error(http.StatusBadRequest, "Invalid Access Token", nil)
|
||||
}
|
||||
|
||||
pubdash, dash, err := api.PublicDashboardService.FindPublicDashboardAndDashboardByAccessToken(
|
||||
c.Req.Context(),
|
||||
accessToken,
|
||||
)
|
||||
if err != nil {
|
||||
return api.handleError(c.Req.Context(), http.StatusInternalServerError, "GetPublicDashboard: failed to get public dashboard", err)
|
||||
}
|
||||
|
||||
meta := dtos.DashboardMeta{
|
||||
Slug: dash.Slug,
|
||||
Type: models.DashTypeDB,
|
||||
CanStar: false,
|
||||
CanSave: false,
|
||||
CanEdit: false,
|
||||
CanAdmin: false,
|
||||
CanDelete: false,
|
||||
Created: dash.Created,
|
||||
Updated: dash.Updated,
|
||||
Version: dash.Version,
|
||||
IsFolder: false,
|
||||
FolderId: dash.FolderId,
|
||||
PublicDashboardAccessToken: pubdash.AccessToken,
|
||||
PublicDashboardUID: pubdash.Uid,
|
||||
}
|
||||
|
||||
dto := dtos.DashboardFullWithMeta{Meta: meta, Dashboard: dash.Data}
|
||||
|
||||
return response.JSON(http.StatusOK, dto)
|
||||
routing.Wrap(api.SavePublicDashboard))
|
||||
}
|
||||
|
||||
// ListPublicDashboards Gets list of public dashboards for an org
|
||||
@ -131,9 +89,9 @@ func (api *Api) ListPublicDashboards(c *models.ReqContext) response.Response {
|
||||
return response.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
// GetPublicDashboardConfig Gets public dashboard configuration for dashboard
|
||||
// GetPublicDashboard Gets public dashboard configuration for dashboard
|
||||
// GET /api/dashboards/uid/:uid/public-config
|
||||
func (api *Api) GetPublicDashboardConfig(c *models.ReqContext) response.Response {
|
||||
func (api *Api) GetPublicDashboard(c *models.ReqContext) response.Response {
|
||||
pdc, err := api.PublicDashboardService.FindByDashboardUid(c.Req.Context(), c.OrgID, web.Params(c.Req)[":dashboardUid"])
|
||||
if err != nil {
|
||||
return api.handleError(c.Req.Context(), http.StatusInternalServerError, "GetPublicDashboardConfig: failed to get public dashboard config", err)
|
||||
@ -141,9 +99,9 @@ func (api *Api) GetPublicDashboardConfig(c *models.ReqContext) response.Response
|
||||
return response.JSON(http.StatusOK, pdc)
|
||||
}
|
||||
|
||||
// SavePublicDashboardConfig Sets public dashboard configuration for dashboard
|
||||
// SavePublicDashboard Sets public dashboard configuration for dashboard
|
||||
// POST /api/dashboards/uid/:uid/public-config
|
||||
func (api *Api) SavePublicDashboardConfig(c *models.ReqContext) response.Response {
|
||||
func (api *Api) SavePublicDashboard(c *models.ReqContext) response.Response {
|
||||
// exit if we don't have a valid dashboardUid
|
||||
dashboardUid := web.Params(c.Req)[":dashboardUid"]
|
||||
if dashboardUid == "" || !util.IsValidShortUID(dashboardUid) {
|
||||
@ -157,7 +115,7 @@ func (api *Api) SavePublicDashboardConfig(c *models.ReqContext) response.Respons
|
||||
|
||||
// Always set the orgID and userID from the session
|
||||
pubdash.OrgId = c.OrgID
|
||||
dto := SavePublicDashboardConfigDTO{
|
||||
dto := SavePublicDashboardDTO{
|
||||
UserId: c.UserID,
|
||||
OrgId: c.OrgID,
|
||||
DashboardUid: dashboardUid,
|
||||
@ -173,54 +131,6 @@ func (api *Api) SavePublicDashboardConfig(c *models.ReqContext) response.Respons
|
||||
return response.JSON(http.StatusOK, pubdash)
|
||||
}
|
||||
|
||||
// QueryPublicDashboard returns all results for a given panel on a public dashboard
|
||||
// POST /api/public/dashboard/:accessToken/panels/:panelId/query
|
||||
func (api *Api) QueryPublicDashboard(c *models.ReqContext) response.Response {
|
||||
accessToken := web.Params(c.Req)[":accessToken"]
|
||||
if !tokens.IsValidAccessToken(accessToken) {
|
||||
return response.Error(http.StatusBadRequest, "Invalid Access Token", nil)
|
||||
}
|
||||
|
||||
panelId, err := strconv.ParseInt(web.Params(c.Req)[":panelId"], 10, 64)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusBadRequest, "QueryPublicDashboard: invalid panel ID", err)
|
||||
}
|
||||
|
||||
reqDTO := PublicDashboardQueryDTO{}
|
||||
if err = web.Bind(c.Req, &reqDTO); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "QueryPublicDashboard: bad request data", err)
|
||||
}
|
||||
|
||||
resp, err := api.PublicDashboardService.GetQueryDataResponse(c.Req.Context(), c.SkipCache, reqDTO, panelId, accessToken)
|
||||
if err != nil {
|
||||
return api.handleError(c.Req.Context(), http.StatusInternalServerError, "QueryPublicDashboard: error running public dashboard panel queries", err)
|
||||
}
|
||||
|
||||
return toJsonStreamingResponse(api.Features, resp)
|
||||
}
|
||||
|
||||
// GetAnnotations returns annotations for a public dashboard
|
||||
// GET /api/public/dashboards/:accessToken/annotations
|
||||
func (api *Api) GetAnnotations(c *models.ReqContext) response.Response {
|
||||
accessToken := web.Params(c.Req)[":accessToken"]
|
||||
if !tokens.IsValidAccessToken(accessToken) {
|
||||
return response.Error(http.StatusBadRequest, "Invalid Access Token", nil)
|
||||
}
|
||||
|
||||
reqDTO := AnnotationsQueryDTO{
|
||||
From: c.QueryInt64("from"),
|
||||
To: c.QueryInt64("to"),
|
||||
}
|
||||
|
||||
annotations, err := api.PublicDashboardService.FindAnnotations(c.Req.Context(), reqDTO, accessToken)
|
||||
|
||||
if err != nil {
|
||||
return api.handleError(c.Req.Context(), http.StatusInternalServerError, "error getting public dashboard annotations", err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, annotations)
|
||||
}
|
||||
|
||||
// util to help us unpack dashboard and publicdashboard errors or use default http code and message
|
||||
// we should look to do some future refactoring of these errors as publicdashboard err is the same as a dashboarderr, just defined in a
|
||||
// different package.
|
||||
|
@ -1,43 +1,23 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashboardStore "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
datasourcesService "github.com/grafana/grafana/pkg/services/datasources/service"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
publicdashboardsStore "github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
||||
"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/web"
|
||||
)
|
||||
|
||||
var userAdmin = &user.SignedInUser{UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, Login: "testAdminUser"}
|
||||
@ -50,76 +30,6 @@ type JsonErrResponse struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func TestAPIGetAnnotations(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
ExpectedHttpResponse int
|
||||
Annotations []AnnotationEvent
|
||||
ServiceError error
|
||||
AccessToken string
|
||||
From string
|
||||
To string
|
||||
ExpectedServiceCalled bool
|
||||
}{
|
||||
{
|
||||
Name: "will return success when there is no error and to and from are provided",
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
Annotations: []AnnotationEvent{{Id: 1}},
|
||||
ServiceError: nil,
|
||||
AccessToken: validAccessToken,
|
||||
From: "123",
|
||||
To: "123",
|
||||
ExpectedServiceCalled: true,
|
||||
},
|
||||
{
|
||||
Name: "will return 500 when service returns an error",
|
||||
ExpectedHttpResponse: http.StatusInternalServerError,
|
||||
Annotations: nil,
|
||||
ServiceError: errors.New("an error happened"),
|
||||
AccessToken: validAccessToken,
|
||||
From: "123",
|
||||
To: "123",
|
||||
ExpectedServiceCalled: true,
|
||||
},
|
||||
{
|
||||
Name: "will return 400 when has an incorrect Access Token",
|
||||
ExpectedHttpResponse: http.StatusBadRequest,
|
||||
Annotations: nil,
|
||||
ServiceError: errors.New("an error happened"),
|
||||
AccessToken: "TooShortAccessToken",
|
||||
From: "123",
|
||||
To: "123",
|
||||
ExpectedServiceCalled: false,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
cfg.RBACEnabled = false
|
||||
service := publicdashboards.NewFakePublicDashboardService(t)
|
||||
|
||||
if test.ExpectedServiceCalled {
|
||||
service.On("FindAnnotations", mock.Anything, mock.Anything, mock.AnythingOfType("string")).
|
||||
Return(test.Annotations, test.ServiceError).Once()
|
||||
}
|
||||
|
||||
testServer := setupTestServer(t, cfg, featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards), service, nil, anonymousUser)
|
||||
|
||||
path := fmt.Sprintf("/api/public/dashboards/%s/annotations?from=%s&to=%s", test.AccessToken, test.From, test.To)
|
||||
response := callAPI(testServer, http.MethodGet, path, nil, t)
|
||||
|
||||
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
|
||||
|
||||
if test.ExpectedHttpResponse == http.StatusOK {
|
||||
var items []AnnotationEvent
|
||||
err := json.Unmarshal(response.Body.Bytes(), &items)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, items, test.Annotations)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIFeatureFlag(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
@ -142,7 +52,7 @@ func TestAPIFeatureFlag(t *testing.T) {
|
||||
Path: "/api/dashboards/public-dashboards",
|
||||
},
|
||||
{
|
||||
Name: "API: Get Public Dashboard Config",
|
||||
Name: "API: Get Public Dashboard",
|
||||
Method: http.MethodPost,
|
||||
Path: "/api/dashboards/uid/abc123/public-dashboards",
|
||||
},
|
||||
@ -239,95 +149,6 @@ func TestAPIListPublicDashboard(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAPIGetPublicDashboard(t *testing.T) {
|
||||
DashboardUid := "dashboard-abcd1234"
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
AccessToken string
|
||||
ExpectedHttpResponse int
|
||||
DashboardResult *models.Dashboard
|
||||
Err error
|
||||
FixedErrorResponse string
|
||||
}{
|
||||
{
|
||||
Name: "It gets a public dashboard",
|
||||
AccessToken: validAccessToken,
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
DashboardResult: &models.Dashboard{
|
||||
Data: simplejson.NewFromAny(map[string]interface{}{
|
||||
"Uid": DashboardUid,
|
||||
}),
|
||||
},
|
||||
Err: nil,
|
||||
FixedErrorResponse: "",
|
||||
},
|
||||
{
|
||||
Name: "It should return 404 if no public dashboard",
|
||||
AccessToken: validAccessToken,
|
||||
ExpectedHttpResponse: http.StatusNotFound,
|
||||
DashboardResult: nil,
|
||||
Err: ErrPublicDashboardNotFound,
|
||||
FixedErrorResponse: "",
|
||||
},
|
||||
{
|
||||
Name: "It should return 400 if it is an invalid access token",
|
||||
AccessToken: "SomeInvalidAccessToken",
|
||||
ExpectedHttpResponse: http.StatusBadRequest,
|
||||
DashboardResult: nil,
|
||||
Err: nil,
|
||||
FixedErrorResponse: "{\"message\":\"Invalid Access Token\"}",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
service := publicdashboards.NewFakePublicDashboardService(t)
|
||||
service.On("FindPublicDashboardAndDashboardByAccessToken", mock.Anything, mock.AnythingOfType("string")).
|
||||
Return(&PublicDashboard{}, test.DashboardResult, test.Err).Maybe()
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
cfg.RBACEnabled = false
|
||||
|
||||
testServer := setupTestServer(
|
||||
t,
|
||||
cfg,
|
||||
featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards),
|
||||
service,
|
||||
nil,
|
||||
anonymousUser,
|
||||
)
|
||||
|
||||
response := callAPI(testServer, http.MethodGet,
|
||||
fmt.Sprintf("/api/public/dashboards/%s", test.AccessToken),
|
||||
nil,
|
||||
t,
|
||||
)
|
||||
|
||||
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
|
||||
|
||||
if test.Err == nil && test.FixedErrorResponse == "" {
|
||||
var dashResp dtos.DashboardFullWithMeta
|
||||
err := json.Unmarshal(response.Body.Bytes(), &dashResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, DashboardUid, dashResp.Dashboard.Get("Uid").MustString())
|
||||
assert.Equal(t, false, dashResp.Meta.CanEdit)
|
||||
assert.Equal(t, false, dashResp.Meta.CanDelete)
|
||||
assert.Equal(t, false, dashResp.Meta.CanSave)
|
||||
} else if test.FixedErrorResponse != "" {
|
||||
require.Equal(t, test.ExpectedHttpResponse, response.Code)
|
||||
require.JSONEq(t, "{\"message\":\"Invalid Access Token\"}", response.Body.String())
|
||||
} else {
|
||||
var errResp JsonErrResponse
|
||||
err := json.Unmarshal(response.Body.Bytes(), &errResp)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.Err.Error(), errResp.Error)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetPublicDashboardConfig(t *testing.T) {
|
||||
pubdash := &PublicDashboard{IsEnabled: true}
|
||||
|
||||
testCases := []struct {
|
||||
@ -341,7 +162,7 @@ func TestAPIGetPublicDashboardConfig(t *testing.T) {
|
||||
ShouldCallService bool
|
||||
}{
|
||||
{
|
||||
Name: "retrieves public dashboard config when dashboard is found",
|
||||
Name: "retrieves public dashboard when dashboard is found",
|
||||
DashboardUid: "1",
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
PublicDashboardResult: pubdash,
|
||||
@ -371,7 +192,7 @@ func TestAPIGetPublicDashboardConfig(t *testing.T) {
|
||||
ShouldCallService: true,
|
||||
},
|
||||
{
|
||||
Name: "retrieves public dashboard config when dashboard is found RBAC on",
|
||||
Name: "retrieves public dashboard when dashboard is found RBAC on",
|
||||
DashboardUid: "1",
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
PublicDashboardResult: pubdash,
|
||||
@ -432,72 +253,72 @@ func TestAPIGetPublicDashboardConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestApiSavePublicDashboardConfig(t *testing.T) {
|
||||
func TestApiSavePublicDashboard(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
DashboardUid string
|
||||
publicDashboardConfig *PublicDashboard
|
||||
ExpectedHttpResponse int
|
||||
SaveDashboardErr error
|
||||
User *user.SignedInUser
|
||||
AccessControlEnabled bool
|
||||
ShouldCallService bool
|
||||
Name string
|
||||
DashboardUid string
|
||||
publicDashboard *PublicDashboard
|
||||
ExpectedHttpResponse int
|
||||
SaveDashboardErr error
|
||||
User *user.SignedInUser
|
||||
AccessControlEnabled bool
|
||||
ShouldCallService bool
|
||||
}{
|
||||
{
|
||||
Name: "returns 200 when update persists",
|
||||
DashboardUid: "1",
|
||||
publicDashboardConfig: &PublicDashboard{IsEnabled: true},
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
SaveDashboardErr: nil,
|
||||
User: userAdmin,
|
||||
AccessControlEnabled: false,
|
||||
ShouldCallService: true,
|
||||
Name: "returns 200 when update persists",
|
||||
DashboardUid: "1",
|
||||
publicDashboard: &PublicDashboard{IsEnabled: true},
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
SaveDashboardErr: nil,
|
||||
User: userAdmin,
|
||||
AccessControlEnabled: false,
|
||||
ShouldCallService: true,
|
||||
},
|
||||
{
|
||||
Name: "returns 500 when not persisted",
|
||||
ExpectedHttpResponse: http.StatusInternalServerError,
|
||||
publicDashboardConfig: &PublicDashboard{},
|
||||
SaveDashboardErr: errors.New("backend failed to save"),
|
||||
User: userAdmin,
|
||||
AccessControlEnabled: false,
|
||||
ShouldCallService: true,
|
||||
Name: "returns 500 when not persisted",
|
||||
ExpectedHttpResponse: http.StatusInternalServerError,
|
||||
publicDashboard: &PublicDashboard{},
|
||||
SaveDashboardErr: errors.New("backend failed to save"),
|
||||
User: userAdmin,
|
||||
AccessControlEnabled: false,
|
||||
ShouldCallService: true,
|
||||
},
|
||||
{
|
||||
Name: "returns 404 when dashboard not found",
|
||||
ExpectedHttpResponse: http.StatusNotFound,
|
||||
publicDashboardConfig: &PublicDashboard{},
|
||||
SaveDashboardErr: dashboards.ErrDashboardNotFound,
|
||||
User: userAdmin,
|
||||
AccessControlEnabled: false,
|
||||
ShouldCallService: true,
|
||||
Name: "returns 404 when dashboard not found",
|
||||
ExpectedHttpResponse: http.StatusNotFound,
|
||||
publicDashboard: &PublicDashboard{},
|
||||
SaveDashboardErr: dashboards.ErrDashboardNotFound,
|
||||
User: userAdmin,
|
||||
AccessControlEnabled: false,
|
||||
ShouldCallService: true,
|
||||
},
|
||||
{
|
||||
Name: "returns 200 when update persists RBAC on",
|
||||
DashboardUid: "1",
|
||||
publicDashboardConfig: &PublicDashboard{IsEnabled: true},
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
SaveDashboardErr: nil,
|
||||
User: userAdminRBAC,
|
||||
AccessControlEnabled: true,
|
||||
ShouldCallService: true,
|
||||
Name: "returns 200 when update persists RBAC on",
|
||||
DashboardUid: "1",
|
||||
publicDashboard: &PublicDashboard{IsEnabled: true},
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
SaveDashboardErr: nil,
|
||||
User: userAdminRBAC,
|
||||
AccessControlEnabled: true,
|
||||
ShouldCallService: true,
|
||||
},
|
||||
{
|
||||
Name: "returns 403 when no permissions",
|
||||
ExpectedHttpResponse: http.StatusForbidden,
|
||||
publicDashboardConfig: &PublicDashboard{IsEnabled: true},
|
||||
SaveDashboardErr: nil,
|
||||
User: userViewer,
|
||||
AccessControlEnabled: false,
|
||||
ShouldCallService: false,
|
||||
Name: "returns 403 when no permissions",
|
||||
ExpectedHttpResponse: http.StatusForbidden,
|
||||
publicDashboard: &PublicDashboard{IsEnabled: true},
|
||||
SaveDashboardErr: nil,
|
||||
User: userViewer,
|
||||
AccessControlEnabled: false,
|
||||
ShouldCallService: false,
|
||||
},
|
||||
{
|
||||
Name: "returns 403 when no permissions RBAC on",
|
||||
ExpectedHttpResponse: http.StatusForbidden,
|
||||
publicDashboardConfig: &PublicDashboard{IsEnabled: true},
|
||||
SaveDashboardErr: nil,
|
||||
User: userAdmin,
|
||||
AccessControlEnabled: true,
|
||||
ShouldCallService: false,
|
||||
Name: "returns 403 when no permissions RBAC on",
|
||||
ExpectedHttpResponse: http.StatusForbidden,
|
||||
publicDashboard: &PublicDashboard{IsEnabled: true},
|
||||
SaveDashboardErr: nil,
|
||||
User: userAdmin,
|
||||
AccessControlEnabled: true,
|
||||
ShouldCallService: false,
|
||||
},
|
||||
}
|
||||
|
||||
@ -507,7 +328,7 @@ func TestApiSavePublicDashboardConfig(t *testing.T) {
|
||||
|
||||
// this is to avoid AssertExpectations fail at t.Cleanup when the middleware returns before calling the service
|
||||
if test.ShouldCallService {
|
||||
service.On("Save", mock.Anything, mock.Anything, mock.AnythingOfType("*models.SavePublicDashboardConfigDTO")).
|
||||
service.On("Save", mock.Anything, mock.Anything, mock.AnythingOfType("*models.SavePublicDashboardDTO")).
|
||||
Return(&PublicDashboard{IsEnabled: true}, test.SaveDashboardErr)
|
||||
}
|
||||
|
||||
@ -535,240 +356,10 @@ func TestApiSavePublicDashboardConfig(t *testing.T) {
|
||||
|
||||
//check the result if it's a 200
|
||||
if response.Code == http.StatusOK {
|
||||
val, err := json.Marshal(test.publicDashboardConfig)
|
||||
val, err := json.Marshal(test.publicDashboard)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, string(val), response.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// `/public/dashboards/:uid/query“ endpoint test
|
||||
func TestAPIQueryPublicDashboard(t *testing.T) {
|
||||
mockedResponse := &backend.QueryDataResponse{
|
||||
Responses: map[string]backend.DataResponse{
|
||||
"test": {
|
||||
Frames: data.Frames{
|
||||
&data.Frame{
|
||||
Name: "anyDataFrame",
|
||||
Fields: []*data.Field{
|
||||
data.NewField("anyGroupName", nil, []*string{
|
||||
aws.String("group_a"), aws.String("group_b"), aws.String("group_c"),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
Error: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedResponse := `{
|
||||
"results": {
|
||||
"test": {
|
||||
"frames": [
|
||||
{
|
||||
"schema": {
|
||||
"name": "anyDataFrame",
|
||||
"fields": [
|
||||
{
|
||||
"name": "anyGroupName",
|
||||
"type": "string",
|
||||
"typeInfo": {
|
||||
"frame": "string",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"values": [
|
||||
[
|
||||
"group_a",
|
||||
"group_b",
|
||||
"group_c"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
setup := func(enabled bool) (*web.Mux, *publicdashboards.FakePublicDashboardService) {
|
||||
service := publicdashboards.NewFakePublicDashboardService(t)
|
||||
cfg := setting.NewCfg()
|
||||
cfg.RBACEnabled = false
|
||||
|
||||
testServer := setupTestServer(
|
||||
t,
|
||||
cfg,
|
||||
featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards, enabled),
|
||||
service,
|
||||
nil,
|
||||
anonymousUser,
|
||||
)
|
||||
|
||||
return testServer, service
|
||||
}
|
||||
|
||||
t.Run("Status code is 400 when the panel ID is invalid", func(t *testing.T) {
|
||||
server, _ := setup(true)
|
||||
path := fmt.Sprintf("/api/public/dashboards/%s/panels/notanumber/query", validAccessToken)
|
||||
resp := callAPI(server, http.MethodPost, path, strings.NewReader("{}"), t)
|
||||
require.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
})
|
||||
|
||||
t.Run("Status code is 400 when the access token is invalid", func(t *testing.T) {
|
||||
server, _ := setup(true)
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath("SomeInvalidAccessToken"), strings.NewReader("{}"), t)
|
||||
require.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
require.JSONEq(t, "{\"message\":\"Invalid Access Token\"}", resp.Body.String())
|
||||
})
|
||||
|
||||
t.Run("Status code is 400 when the intervalMS is lesser than 0", func(t *testing.T) {
|
||||
server, fakeDashboardService := setup(true)
|
||||
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, ErrPublicDashboardBadRequest)
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader(`{"intervalMs":-100,"maxDataPoints":1000}`), t)
|
||||
require.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
})
|
||||
|
||||
t.Run("Status code is 400 when the maxDataPoints is lesser than 0", func(t *testing.T) {
|
||||
server, fakeDashboardService := setup(true)
|
||||
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, ErrPublicDashboardBadRequest)
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader(`{"intervalMs":100,"maxDataPoints":-1000}`), t)
|
||||
require.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
})
|
||||
|
||||
t.Run("Returns query data when feature toggle is enabled", func(t *testing.T) {
|
||||
server, fakeDashboardService := setup(true)
|
||||
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(mockedResponse, nil)
|
||||
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader("{}"), t)
|
||||
|
||||
require.JSONEq(
|
||||
t,
|
||||
expectedResponse,
|
||||
resp.Body.String(),
|
||||
)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
})
|
||||
|
||||
t.Run("Status code is 500 when the query fails", func(t *testing.T) {
|
||||
server, fakeDashboardService := setup(true)
|
||||
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, fmt.Errorf("error"))
|
||||
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader("{}"), t)
|
||||
require.Equal(t, http.StatusInternalServerError, resp.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func getValidQueryPath(accessToken string) string {
|
||||
return fmt.Sprintf("/api/public/dashboards/%s/panels/2/query", accessToken)
|
||||
}
|
||||
|
||||
func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T) {
|
||||
db := db.InitTestDB(t)
|
||||
|
||||
cacheService := datasourcesService.ProvideCacheService(localcache.ProvideService(), db)
|
||||
qds := buildQueryDataService(t, cacheService, nil, db)
|
||||
dsStore := datasourcesService.CreateStore(db, log.New("publicdashboards.test"))
|
||||
_ = dsStore.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{
|
||||
Uid: "ds1",
|
||||
OrgId: 1,
|
||||
Name: "laban",
|
||||
Type: datasources.DS_MYSQL,
|
||||
Access: datasources.DS_ACCESS_DIRECT,
|
||||
Url: "http://test",
|
||||
Database: "site",
|
||||
ReadOnly: true,
|
||||
})
|
||||
|
||||
// Create Dashboard
|
||||
saveDashboardCmd := models.SaveDashboardCommand{
|
||||
OrgId: 1,
|
||||
FolderId: 1,
|
||||
IsFolder: false,
|
||||
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
||||
"id": nil,
|
||||
"title": "test",
|
||||
"panels": []map[string]interface{}{
|
||||
{
|
||||
"id": 1,
|
||||
"targets": []map[string]interface{}{
|
||||
{
|
||||
"datasource": map[string]string{
|
||||
"type": "mysql",
|
||||
"uid": "ds1",
|
||||
},
|
||||
"refId": "A",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
// create dashboard
|
||||
dashboardStoreService := dashboardStore.ProvideDashboardStore(db, db.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db, db.Cfg))
|
||||
dashboard, err := dashboardStoreService.SaveDashboard(context.Background(), saveDashboardCmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create public dashboard
|
||||
savePubDashboardCmd := &SavePublicDashboardConfigDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
PublicDashboard: &PublicDashboard{
|
||||
IsEnabled: true,
|
||||
},
|
||||
}
|
||||
|
||||
annotationsService := annotationstest.NewFakeAnnotationsRepo()
|
||||
|
||||
// create public dashboard
|
||||
store := publicdashboardsStore.ProvideStore(db)
|
||||
cfg := setting.NewCfg()
|
||||
ac := acmock.New()
|
||||
cfg.RBACEnabled = false
|
||||
service := publicdashboardsService.ProvideService(cfg, store, qds, annotationsService, ac)
|
||||
pubdash, err := service.Save(context.Background(), &user.SignedInUser{}, savePubDashboardCmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// setup test server
|
||||
server := setupTestServer(t,
|
||||
cfg,
|
||||
featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards),
|
||||
service,
|
||||
db,
|
||||
anonymousUser,
|
||||
)
|
||||
|
||||
resp := callAPI(server, http.MethodPost,
|
||||
fmt.Sprintf("/api/public/dashboards/%s/panels/1/query", pubdash.AccessToken),
|
||||
strings.NewReader(`{}`),
|
||||
t,
|
||||
)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(
|
||||
t,
|
||||
`{
|
||||
"results": {
|
||||
"A": {
|
||||
"frames": [
|
||||
{
|
||||
"data": {
|
||||
"values": []
|
||||
},
|
||||
"schema": {
|
||||
"fields": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}`,
|
||||
resp.Body.String(),
|
||||
)
|
||||
}
|
||||
|
100
pkg/services/publicdashboards/api/query.go
Normal file
100
pkg/services/publicdashboards/api/query.go
Normal file
@ -0,0 +1,100 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
// ViewPublicDashboard Gets public dashboard
|
||||
// GET /api/public/dashboards/:accessToken
|
||||
func (api *Api) ViewPublicDashboard(c *models.ReqContext) response.Response {
|
||||
accessToken := web.Params(c.Req)[":accessToken"]
|
||||
|
||||
if !tokens.IsValidAccessToken(accessToken) {
|
||||
return response.Error(http.StatusBadRequest, "Invalid Access Token", nil)
|
||||
}
|
||||
|
||||
pubdash, dash, err := api.PublicDashboardService.FindPublicDashboardAndDashboardByAccessToken(
|
||||
c.Req.Context(),
|
||||
accessToken,
|
||||
)
|
||||
if err != nil {
|
||||
return api.handleError(c.Req.Context(), http.StatusInternalServerError, "ViewPublicDashboard: failed to get public dashboard", err)
|
||||
}
|
||||
|
||||
meta := dtos.DashboardMeta{
|
||||
Slug: dash.Slug,
|
||||
Type: models.DashTypeDB,
|
||||
CanStar: false,
|
||||
CanSave: false,
|
||||
CanEdit: false,
|
||||
CanAdmin: false,
|
||||
CanDelete: false,
|
||||
Created: dash.Created,
|
||||
Updated: dash.Updated,
|
||||
Version: dash.Version,
|
||||
IsFolder: false,
|
||||
FolderId: dash.FolderId,
|
||||
PublicDashboardAccessToken: pubdash.AccessToken,
|
||||
PublicDashboardUID: pubdash.Uid,
|
||||
}
|
||||
|
||||
dto := dtos.DashboardFullWithMeta{Meta: meta, Dashboard: dash.Data}
|
||||
|
||||
return response.JSON(http.StatusOK, dto)
|
||||
}
|
||||
|
||||
// QueryPublicDashboard returns all results for a given panel on a public dashboard
|
||||
// POST /api/public/dashboard/:accessToken/panels/:panelId/query
|
||||
func (api *Api) QueryPublicDashboard(c *models.ReqContext) response.Response {
|
||||
accessToken := web.Params(c.Req)[":accessToken"]
|
||||
if !tokens.IsValidAccessToken(accessToken) {
|
||||
return response.Error(http.StatusBadRequest, "Invalid Access Token", nil)
|
||||
}
|
||||
|
||||
panelId, err := strconv.ParseInt(web.Params(c.Req)[":panelId"], 10, 64)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusBadRequest, "QueryPublicDashboard: invalid panel ID", err)
|
||||
}
|
||||
|
||||
reqDTO := PublicDashboardQueryDTO{}
|
||||
if err = web.Bind(c.Req, &reqDTO); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "QueryPublicDashboard: bad request data", err)
|
||||
}
|
||||
|
||||
resp, err := api.PublicDashboardService.GetQueryDataResponse(c.Req.Context(), c.SkipCache, reqDTO, panelId, accessToken)
|
||||
if err != nil {
|
||||
return api.handleError(c.Req.Context(), http.StatusInternalServerError, "QueryPublicDashboard: error running public dashboard panel queries", err)
|
||||
}
|
||||
|
||||
return toJsonStreamingResponse(api.Features, resp)
|
||||
}
|
||||
|
||||
// GetAnnotations returns annotations for a public dashboard
|
||||
// GET /api/public/dashboards/:accessToken/annotations
|
||||
func (api *Api) GetAnnotations(c *models.ReqContext) response.Response {
|
||||
accessToken := web.Params(c.Req)[":accessToken"]
|
||||
if !tokens.IsValidAccessToken(accessToken) {
|
||||
return response.Error(http.StatusBadRequest, "Invalid Access Token", nil)
|
||||
}
|
||||
|
||||
reqDTO := AnnotationsQueryDTO{
|
||||
From: c.QueryInt64("from"),
|
||||
To: c.QueryInt64("to"),
|
||||
}
|
||||
|
||||
annotations, err := api.PublicDashboardService.FindAnnotations(c.Req.Context(), reqDTO, accessToken)
|
||||
|
||||
if err != nil {
|
||||
return api.handleError(c.Req.Context(), http.StatusInternalServerError, "error getting public dashboard annotations", err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, annotations)
|
||||
}
|
427
pkg/services/publicdashboards/api/query_test.go
Normal file
427
pkg/services/publicdashboards/api/query_test.go
Normal file
@ -0,0 +1,427 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
|
||||
dashboardStore "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
datasourcesService "github.com/grafana/grafana/pkg/services/datasources/service"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
publicdashboardsStore "github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
||||
"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/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAPIViewPublicDashboard(t *testing.T) {
|
||||
DashboardUid := "dashboard-abcd1234"
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
AccessToken string
|
||||
ExpectedHttpResponse int
|
||||
DashboardResult *models.Dashboard
|
||||
Err error
|
||||
FixedErrorResponse string
|
||||
}{
|
||||
{
|
||||
Name: "It gets a public dashboard",
|
||||
AccessToken: validAccessToken,
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
DashboardResult: &models.Dashboard{
|
||||
Data: simplejson.NewFromAny(map[string]interface{}{
|
||||
"Uid": DashboardUid,
|
||||
}),
|
||||
},
|
||||
Err: nil,
|
||||
FixedErrorResponse: "",
|
||||
},
|
||||
{
|
||||
Name: "It should return 404 if no public dashboard",
|
||||
AccessToken: validAccessToken,
|
||||
ExpectedHttpResponse: http.StatusNotFound,
|
||||
DashboardResult: nil,
|
||||
Err: ErrPublicDashboardNotFound,
|
||||
FixedErrorResponse: "",
|
||||
},
|
||||
{
|
||||
Name: "It should return 400 if it is an invalid access token",
|
||||
AccessToken: "SomeInvalidAccessToken",
|
||||
ExpectedHttpResponse: http.StatusBadRequest,
|
||||
DashboardResult: nil,
|
||||
Err: nil,
|
||||
FixedErrorResponse: "{\"message\":\"Invalid Access Token\"}",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
service := publicdashboards.NewFakePublicDashboardService(t)
|
||||
service.On("FindPublicDashboardAndDashboardByAccessToken", mock.Anything, mock.AnythingOfType("string")).
|
||||
Return(&PublicDashboard{}, test.DashboardResult, test.Err).Maybe()
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
cfg.RBACEnabled = false
|
||||
|
||||
testServer := setupTestServer(
|
||||
t,
|
||||
cfg,
|
||||
featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards),
|
||||
service,
|
||||
nil,
|
||||
anonymousUser,
|
||||
)
|
||||
|
||||
response := callAPI(testServer, http.MethodGet,
|
||||
fmt.Sprintf("/api/public/dashboards/%s", test.AccessToken),
|
||||
nil,
|
||||
t,
|
||||
)
|
||||
|
||||
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
|
||||
|
||||
if test.Err == nil && test.FixedErrorResponse == "" {
|
||||
var dashResp dtos.DashboardFullWithMeta
|
||||
err := json.Unmarshal(response.Body.Bytes(), &dashResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, DashboardUid, dashResp.Dashboard.Get("Uid").MustString())
|
||||
assert.Equal(t, false, dashResp.Meta.CanEdit)
|
||||
assert.Equal(t, false, dashResp.Meta.CanDelete)
|
||||
assert.Equal(t, false, dashResp.Meta.CanSave)
|
||||
} else if test.FixedErrorResponse != "" {
|
||||
require.Equal(t, test.ExpectedHttpResponse, response.Code)
|
||||
require.JSONEq(t, "{\"message\":\"Invalid Access Token\"}", response.Body.String())
|
||||
} else {
|
||||
var errResp JsonErrResponse
|
||||
err := json.Unmarshal(response.Body.Bytes(), &errResp)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.Err.Error(), errResp.Error)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// `/public/dashboards/:uid/query“ endpoint test
|
||||
func TestAPIQueryPublicDashboard(t *testing.T) {
|
||||
mockedResponse := &backend.QueryDataResponse{
|
||||
Responses: map[string]backend.DataResponse{
|
||||
"test": {
|
||||
Frames: data.Frames{
|
||||
&data.Frame{
|
||||
Name: "anyDataFrame",
|
||||
Fields: []*data.Field{
|
||||
data.NewField("anyGroupName", nil, []*string{
|
||||
aws.String("group_a"), aws.String("group_b"), aws.String("group_c"),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
Error: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedResponse := `{
|
||||
"results": {
|
||||
"test": {
|
||||
"frames": [
|
||||
{
|
||||
"schema": {
|
||||
"name": "anyDataFrame",
|
||||
"fields": [
|
||||
{
|
||||
"name": "anyGroupName",
|
||||
"type": "string",
|
||||
"typeInfo": {
|
||||
"frame": "string",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"values": [
|
||||
[
|
||||
"group_a",
|
||||
"group_b",
|
||||
"group_c"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
setup := func(enabled bool) (*web.Mux, *publicdashboards.FakePublicDashboardService) {
|
||||
service := publicdashboards.NewFakePublicDashboardService(t)
|
||||
cfg := setting.NewCfg()
|
||||
cfg.RBACEnabled = false
|
||||
|
||||
testServer := setupTestServer(
|
||||
t,
|
||||
cfg,
|
||||
featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards, enabled),
|
||||
service,
|
||||
nil,
|
||||
anonymousUser,
|
||||
)
|
||||
|
||||
return testServer, service
|
||||
}
|
||||
|
||||
t.Run("Status code is 400 when the panel ID is invalid", func(t *testing.T) {
|
||||
server, _ := setup(true)
|
||||
path := fmt.Sprintf("/api/public/dashboards/%s/panels/notanumber/query", validAccessToken)
|
||||
resp := callAPI(server, http.MethodPost, path, strings.NewReader("{}"), t)
|
||||
require.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
})
|
||||
|
||||
t.Run("Status code is 400 when the access token is invalid", func(t *testing.T) {
|
||||
server, _ := setup(true)
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath("SomeInvalidAccessToken"), strings.NewReader("{}"), t)
|
||||
require.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
require.JSONEq(t, "{\"message\":\"Invalid Access Token\"}", resp.Body.String())
|
||||
})
|
||||
|
||||
t.Run("Status code is 400 when the intervalMS is lesser than 0", func(t *testing.T) {
|
||||
server, fakeDashboardService := setup(true)
|
||||
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, ErrPublicDashboardBadRequest)
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader(`{"intervalMs":-100,"maxDataPoints":1000}`), t)
|
||||
require.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
})
|
||||
|
||||
t.Run("Status code is 400 when the maxDataPoints is lesser than 0", func(t *testing.T) {
|
||||
server, fakeDashboardService := setup(true)
|
||||
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, ErrPublicDashboardBadRequest)
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader(`{"intervalMs":100,"maxDataPoints":-1000}`), t)
|
||||
require.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
})
|
||||
|
||||
t.Run("Returns query data when feature toggle is enabled", func(t *testing.T) {
|
||||
server, fakeDashboardService := setup(true)
|
||||
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(mockedResponse, nil)
|
||||
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader("{}"), t)
|
||||
|
||||
require.JSONEq(
|
||||
t,
|
||||
expectedResponse,
|
||||
resp.Body.String(),
|
||||
)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
})
|
||||
|
||||
t.Run("Status code is 500 when the query fails", func(t *testing.T) {
|
||||
server, fakeDashboardService := setup(true)
|
||||
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, fmt.Errorf("error"))
|
||||
|
||||
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader("{}"), t)
|
||||
require.Equal(t, http.StatusInternalServerError, resp.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func getValidQueryPath(accessToken string) string {
|
||||
return fmt.Sprintf("/api/public/dashboards/%s/panels/2/query", accessToken)
|
||||
}
|
||||
|
||||
func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T) {
|
||||
db := db.InitTestDB(t)
|
||||
|
||||
cacheService := datasourcesService.ProvideCacheService(localcache.ProvideService(), db)
|
||||
qds := buildQueryDataService(t, cacheService, nil, db)
|
||||
dsStore := datasourcesService.CreateStore(db, log.New("publicdashboards.test"))
|
||||
_ = dsStore.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{
|
||||
Uid: "ds1",
|
||||
OrgId: 1,
|
||||
Name: "laban",
|
||||
Type: datasources.DS_MYSQL,
|
||||
Access: datasources.DS_ACCESS_DIRECT,
|
||||
Url: "http://test",
|
||||
Database: "site",
|
||||
ReadOnly: true,
|
||||
})
|
||||
|
||||
// Create Dashboard
|
||||
saveDashboardCmd := models.SaveDashboardCommand{
|
||||
OrgId: 1,
|
||||
FolderId: 1,
|
||||
IsFolder: false,
|
||||
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
||||
"id": nil,
|
||||
"title": "test",
|
||||
"panels": []map[string]interface{}{
|
||||
{
|
||||
"id": 1,
|
||||
"targets": []map[string]interface{}{
|
||||
{
|
||||
"datasource": map[string]string{
|
||||
"type": "mysql",
|
||||
"uid": "ds1",
|
||||
},
|
||||
"refId": "A",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
// create dashboard
|
||||
dashboardStoreService := dashboardStore.ProvideDashboardStore(db, db.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db, db.Cfg))
|
||||
dashboard, err := dashboardStoreService.SaveDashboard(context.Background(), saveDashboardCmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create public dashboard
|
||||
savePubDashboardCmd := &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
PublicDashboard: &PublicDashboard{
|
||||
IsEnabled: true,
|
||||
},
|
||||
}
|
||||
|
||||
annotationsService := annotationstest.NewFakeAnnotationsRepo()
|
||||
|
||||
// create public dashboard
|
||||
store := publicdashboardsStore.ProvideStore(db)
|
||||
cfg := setting.NewCfg()
|
||||
ac := acmock.New()
|
||||
cfg.RBACEnabled = false
|
||||
service := publicdashboardsService.ProvideService(cfg, store, qds, annotationsService, ac)
|
||||
pubdash, err := service.Save(context.Background(), &user.SignedInUser{}, savePubDashboardCmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// setup test server
|
||||
server := setupTestServer(t,
|
||||
cfg,
|
||||
featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards),
|
||||
service,
|
||||
db,
|
||||
anonymousUser,
|
||||
)
|
||||
|
||||
resp := callAPI(server, http.MethodPost,
|
||||
fmt.Sprintf("/api/public/dashboards/%s/panels/1/query", pubdash.AccessToken),
|
||||
strings.NewReader(`{}`),
|
||||
t,
|
||||
)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(
|
||||
t,
|
||||
`{
|
||||
"results": {
|
||||
"A": {
|
||||
"frames": [
|
||||
{
|
||||
"data": {
|
||||
"values": []
|
||||
},
|
||||
"schema": {
|
||||
"fields": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}`,
|
||||
resp.Body.String(),
|
||||
)
|
||||
}
|
||||
|
||||
func TestAPIGetAnnotations(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
ExpectedHttpResponse int
|
||||
Annotations []AnnotationEvent
|
||||
ServiceError error
|
||||
AccessToken string
|
||||
From string
|
||||
To string
|
||||
ExpectedServiceCalled bool
|
||||
}{
|
||||
{
|
||||
Name: "will return success when there is no error and to and from are provided",
|
||||
ExpectedHttpResponse: http.StatusOK,
|
||||
Annotations: []AnnotationEvent{{Id: 1}},
|
||||
ServiceError: nil,
|
||||
AccessToken: validAccessToken,
|
||||
From: "123",
|
||||
To: "123",
|
||||
ExpectedServiceCalled: true,
|
||||
},
|
||||
{
|
||||
Name: "will return 500 when service returns an error",
|
||||
ExpectedHttpResponse: http.StatusInternalServerError,
|
||||
Annotations: nil,
|
||||
ServiceError: errors.New("an error happened"),
|
||||
AccessToken: validAccessToken,
|
||||
From: "123",
|
||||
To: "123",
|
||||
ExpectedServiceCalled: true,
|
||||
},
|
||||
{
|
||||
Name: "will return 400 when has an incorrect Access Token",
|
||||
ExpectedHttpResponse: http.StatusBadRequest,
|
||||
Annotations: nil,
|
||||
ServiceError: errors.New("an error happened"),
|
||||
AccessToken: "TooShortAccessToken",
|
||||
From: "123",
|
||||
To: "123",
|
||||
ExpectedServiceCalled: false,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
cfg.RBACEnabled = false
|
||||
service := publicdashboards.NewFakePublicDashboardService(t)
|
||||
|
||||
if test.ExpectedServiceCalled {
|
||||
service.On("FindAnnotations", mock.Anything, mock.Anything, mock.AnythingOfType("string")).
|
||||
Return(test.Annotations, test.ServiceError).Once()
|
||||
}
|
||||
|
||||
testServer := setupTestServer(t, cfg, featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards), service, nil, anonymousUser)
|
||||
|
||||
path := fmt.Sprintf("/api/public/dashboards/%s/annotations?from=%s&to=%s", test.AccessToken, test.From, test.To)
|
||||
response := callAPI(testServer, http.MethodGet, path, nil, t)
|
||||
|
||||
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
|
||||
|
||||
if test.ExpectedHttpResponse == http.StatusOK {
|
||||
var items []AnnotationEvent
|
||||
err := json.Unmarshal(response.Body.Bytes(), &items)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, items, test.Annotations)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -71,7 +71,7 @@ func (d *PublicDashboardStoreImpl) FindDashboard(ctx context.Context, dashboardU
|
||||
return dashboard, err
|
||||
}
|
||||
|
||||
// Find Returns public dashboard configuration by Uid or nil if not found
|
||||
// Find Returns public dashboard by Uid or nil if not found
|
||||
func (d *PublicDashboardStoreImpl) Find(ctx context.Context, uid string) (*PublicDashboard, error) {
|
||||
if uid == "" {
|
||||
return nil, nil
|
||||
@ -121,7 +121,7 @@ func (d *PublicDashboardStoreImpl) FindByAccessToken(ctx context.Context, access
|
||||
return pdRes, err
|
||||
}
|
||||
|
||||
// FindByDashboardUid Retrieves public dashboard configuration by dashboard uid
|
||||
// FindByDashboardUid Retrieves public dashboard by dashboard uid
|
||||
func (d *PublicDashboardStoreImpl) FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error) {
|
||||
if dashboardUid == "" {
|
||||
return nil, dashboards.ErrDashboardIdentifierNotSet
|
||||
@ -148,8 +148,8 @@ func (d *PublicDashboardStoreImpl) FindByDashboardUid(ctx context.Context, orgId
|
||||
return pdRes, err
|
||||
}
|
||||
|
||||
// Save Persists public dashboard configuration
|
||||
func (d *PublicDashboardStoreImpl) Save(ctx context.Context, cmd SavePublicDashboardConfigCommand) error {
|
||||
// Save Persists public dashboard
|
||||
func (d *PublicDashboardStoreImpl) Save(ctx context.Context, cmd SavePublicDashboardCommand) error {
|
||||
if cmd.PublicDashboard.DashboardUid == "" {
|
||||
return dashboards.ErrDashboardIdentifierNotSet
|
||||
}
|
||||
@ -166,8 +166,8 @@ func (d *PublicDashboardStoreImpl) Save(ctx context.Context, cmd SavePublicDashb
|
||||
return err
|
||||
}
|
||||
|
||||
// Update updates existing public dashboard configuration
|
||||
func (d *PublicDashboardStoreImpl) Update(ctx context.Context, cmd SavePublicDashboardConfigCommand) error {
|
||||
// Update updates existing public dashboard
|
||||
func (d *PublicDashboardStoreImpl) Update(ctx context.Context, cmd SavePublicDashboardCommand) error {
|
||||
err := d.sqlStore.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
timeSettingsJSON, err := json.Marshal(cmd.PublicDashboard.TimeSettings)
|
||||
if err != nil {
|
||||
|
@ -104,7 +104,7 @@ func TestIntegrationExistsEnabledByAccessToken(t *testing.T) {
|
||||
t.Run("ExistsEnabledByAccessToken will return true when at least one public dashboard has a matching access token", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: true,
|
||||
Uid: "abc123",
|
||||
@ -126,7 +126,7 @@ func TestIntegrationExistsEnabledByAccessToken(t *testing.T) {
|
||||
t.Run("ExistsEnabledByAccessToken will return false when IsEnabled=false", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: false,
|
||||
Uid: "abc123",
|
||||
@ -172,7 +172,7 @@ func TestIntegrationExistsEnabledByDashboardUid(t *testing.T) {
|
||||
t.Run("ExistsEnabledByDashboardUid Will return true when dashboard has at least one enabled public dashboard", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: true,
|
||||
Uid: "abc123",
|
||||
@ -194,7 +194,7 @@ func TestIntegrationExistsEnabledByDashboardUid(t *testing.T) {
|
||||
t.Run("ExistsEnabledByDashboardUid will return false when dashboard has public dashboards but they are not enabled", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: false,
|
||||
Uid: "abc123",
|
||||
@ -244,7 +244,7 @@ func TestIntegrationFindByDashboardUid(t *testing.T) {
|
||||
|
||||
t.Run("returns along with public dashboard when exists", func(t *testing.T) {
|
||||
setup()
|
||||
cmd := SavePublicDashboardConfigCommand{
|
||||
cmd := SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: true,
|
||||
Uid: "pubdash-uid",
|
||||
@ -295,7 +295,7 @@ func TestIntegrationSavePublicDashboard(t *testing.T) {
|
||||
|
||||
t.Run("saves new public dashboard", func(t *testing.T) {
|
||||
setup()
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: true,
|
||||
AnnotationsEnabled: true,
|
||||
@ -324,7 +324,7 @@ func TestIntegrationSavePublicDashboard(t *testing.T) {
|
||||
|
||||
t.Run("guards from saving without dashboardUid", func(t *testing.T) {
|
||||
setup()
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: true,
|
||||
Uid: "pubdash-uid",
|
||||
@ -360,7 +360,7 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
|
||||
setup()
|
||||
|
||||
pdUid := "asdf1234"
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
Uid: pdUid,
|
||||
DashboardUid: savedDashboard.Uid,
|
||||
@ -376,7 +376,7 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
|
||||
|
||||
// inserting two different public dashboards to test update works and only affect the desired pd by uid
|
||||
anotherPdUid := "anotherUid"
|
||||
err = publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err = publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
Uid: anotherPdUid,
|
||||
DashboardUid: anotherSavedDashboard.Uid,
|
||||
@ -401,7 +401,7 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
|
||||
UpdatedBy: 8,
|
||||
}
|
||||
// update initial record
|
||||
err = publicdashboardStore.Update(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err = publicdashboardStore.Update(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: updatedPublicDashboard,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@ -441,7 +441,7 @@ func TestIntegrationGetOrgIdByAccessToken(t *testing.T) {
|
||||
t.Run("GetOrgIdByAccessToken will OrgId when enabled", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: true,
|
||||
Uid: "abc123",
|
||||
@ -463,7 +463,7 @@ func TestIntegrationGetOrgIdByAccessToken(t *testing.T) {
|
||||
t.Run("GetOrgIdByAccessToken will return 0 when IsEnabled=false", func(t *testing.T) {
|
||||
setup()
|
||||
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardConfigCommand{
|
||||
err := publicdashboardStore.Save(context.Background(), SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
IsEnabled: false,
|
||||
Uid: "abc123",
|
||||
@ -520,7 +520,7 @@ func insertPublicDashboard(t *testing.T, publicdashboardStore *PublicDashboardSt
|
||||
accessToken, err := tokens.GenerateAccessToken()
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd := SavePublicDashboardConfigCommand{
|
||||
cmd := SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
Uid: uid,
|
||||
DashboardUid: dashboardUid,
|
||||
|
@ -151,7 +151,7 @@ func (pd PublicDashboard) BuildTimeSettings(dashboard *models.Dashboard) TimeSet
|
||||
}
|
||||
|
||||
// DTO for transforming user input in the api
|
||||
type SavePublicDashboardConfigDTO struct {
|
||||
type SavePublicDashboardDTO struct {
|
||||
DashboardUid string
|
||||
OrgId int64
|
||||
UserId int64
|
||||
@ -172,6 +172,6 @@ type AnnotationsQueryDTO struct {
|
||||
// COMMANDS
|
||||
//
|
||||
|
||||
type SavePublicDashboardConfigCommand struct {
|
||||
type SavePublicDashboardCommand struct {
|
||||
PublicDashboard PublicDashboard
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.12.1. DO NOT EDIT.
|
||||
|
||||
package publicdashboards
|
||||
|
||||
@ -15,6 +15,8 @@ import (
|
||||
|
||||
pkgmodels "github.com/grafana/grafana/pkg/models"
|
||||
|
||||
testing "testing"
|
||||
|
||||
user "github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
@ -297,11 +299,11 @@ func (_m *FakePublicDashboardService) NewPublicDashboardUid(ctx context.Context)
|
||||
}
|
||||
|
||||
// Save provides a mock function with given fields: ctx, u, dto
|
||||
func (_m *FakePublicDashboardService) Save(ctx context.Context, u *user.SignedInUser, dto *models.SavePublicDashboardConfigDTO) (*models.PublicDashboard, error) {
|
||||
func (_m *FakePublicDashboardService) Save(ctx context.Context, u *user.SignedInUser, dto *models.SavePublicDashboardDTO) (*models.PublicDashboard, error) {
|
||||
ret := _m.Called(ctx, u, dto)
|
||||
|
||||
var r0 *models.PublicDashboard
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, *models.SavePublicDashboardConfigDTO) *models.PublicDashboard); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *user.SignedInUser, *models.SavePublicDashboardDTO) *models.PublicDashboard); ok {
|
||||
r0 = rf(ctx, u, dto)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
@ -310,7 +312,7 @@ func (_m *FakePublicDashboardService) Save(ctx context.Context, u *user.SignedIn
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *user.SignedInUser, *models.SavePublicDashboardConfigDTO) error); ok {
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *user.SignedInUser, *models.SavePublicDashboardDTO) error); ok {
|
||||
r1 = rf(ctx, u, dto)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@ -319,13 +321,8 @@ func (_m *FakePublicDashboardService) Save(ctx context.Context, u *user.SignedIn
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewFakePublicDashboardService interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewFakePublicDashboardService creates a new instance of FakePublicDashboardService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakePublicDashboardService(t mockConstructorTestingTNewFakePublicDashboardService) *FakePublicDashboardService {
|
||||
// NewFakePublicDashboardService creates a new instance of FakePublicDashboardService. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakePublicDashboardService(t testing.TB) *FakePublicDashboardService {
|
||||
mock := &FakePublicDashboardService{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.12.1. DO NOT EDIT.
|
||||
|
||||
package publicdashboards
|
||||
|
||||
@ -9,6 +9,8 @@ import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
pkgmodels "github.com/grafana/grafana/pkg/models"
|
||||
|
||||
testing "testing"
|
||||
)
|
||||
|
||||
// FakePublicDashboardStore is an autogenerated mock type for the Store type
|
||||
@ -195,11 +197,11 @@ func (_m *FakePublicDashboardStore) GetOrgIdByAccessToken(ctx context.Context, a
|
||||
}
|
||||
|
||||
// Save provides a mock function with given fields: ctx, cmd
|
||||
func (_m *FakePublicDashboardStore) Save(ctx context.Context, cmd models.SavePublicDashboardConfigCommand) error {
|
||||
func (_m *FakePublicDashboardStore) Save(ctx context.Context, cmd models.SavePublicDashboardCommand) error {
|
||||
ret := _m.Called(ctx, cmd)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, models.SavePublicDashboardConfigCommand) error); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, models.SavePublicDashboardCommand) error); ok {
|
||||
r0 = rf(ctx, cmd)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
@ -209,11 +211,11 @@ func (_m *FakePublicDashboardStore) Save(ctx context.Context, cmd models.SavePub
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: ctx, cmd
|
||||
func (_m *FakePublicDashboardStore) Update(ctx context.Context, cmd models.SavePublicDashboardConfigCommand) error {
|
||||
func (_m *FakePublicDashboardStore) Update(ctx context.Context, cmd models.SavePublicDashboardCommand) error {
|
||||
ret := _m.Called(ctx, cmd)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, models.SavePublicDashboardConfigCommand) error); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, models.SavePublicDashboardCommand) error); ok {
|
||||
r0 = rf(ctx, cmd)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
@ -222,13 +224,8 @@ func (_m *FakePublicDashboardStore) Update(ctx context.Context, cmd models.SaveP
|
||||
return r0
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewFakePublicDashboardStore interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewFakePublicDashboardStore creates a new instance of FakePublicDashboardStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakePublicDashboardStore(t mockConstructorTestingTNewFakePublicDashboardStore) *FakePublicDashboardStore {
|
||||
// NewFakePublicDashboardStore creates a new instance of FakePublicDashboardStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakePublicDashboardStore(t testing.TB) *FakePublicDashboardStore {
|
||||
mock := &FakePublicDashboardStore{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
|
@ -19,7 +19,7 @@ type Service interface {
|
||||
FindAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error)
|
||||
FindDashboard(ctx context.Context, dashboardUid string, orgId int64) (*models.Dashboard, error)
|
||||
FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]PublicDashboardListResponse, error)
|
||||
Save(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error)
|
||||
Save(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
||||
|
||||
GetMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64, reqDTO PublicDashboardQueryDTO) (dtos.MetricRequest, error)
|
||||
GetQueryDataResponse(ctx context.Context, skipCache bool, reqDTO PublicDashboardQueryDTO, panelId int64, accessToken string) (*backend.QueryDataResponse, error)
|
||||
@ -38,8 +38,8 @@ type Store interface {
|
||||
FindByDashboardUid(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||
FindDashboard(ctx context.Context, dashboardUid string, orgId int64) (*models.Dashboard, error)
|
||||
FindAll(ctx context.Context, orgId int64) ([]PublicDashboardListResponse, error)
|
||||
Save(ctx context.Context, cmd SavePublicDashboardConfigCommand) error
|
||||
Update(ctx context.Context, cmd SavePublicDashboardConfigCommand) error
|
||||
Save(ctx context.Context, cmd SavePublicDashboardCommand) error
|
||||
Update(ctx context.Context, cmd SavePublicDashboardCommand) error
|
||||
|
||||
GetOrgIdByAccessToken(ctx context.Context, accessToken string) (int64, error)
|
||||
ExistsEnabledByAccessToken(ctx context.Context, accessToken string) (bool, error)
|
||||
|
@ -388,7 +388,7 @@ func TestGetQueryDataResponse(t *testing.T) {
|
||||
}}
|
||||
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashWithHiddenQuery", 1, 0, true, []map[string]interface{}{}, customPanels)
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
dto := &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 7,
|
||||
@ -829,7 +829,7 @@ func TestBuildMetricRequest(t *testing.T) {
|
||||
MaxDataPoints: int64(200),
|
||||
}
|
||||
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
dto := &SavePublicDashboardDTO{
|
||||
DashboardUid: publicDashboard.Uid,
|
||||
OrgId: publicDashboard.OrgId,
|
||||
PublicDashboard: &PublicDashboard{
|
||||
@ -843,7 +843,7 @@ func TestBuildMetricRequest(t *testing.T) {
|
||||
publicDashboardPD, err := service.Save(context.Background(), SignedInUser, dto)
|
||||
require.NoError(t, err)
|
||||
|
||||
nonPublicDto := &SavePublicDashboardConfigDTO{
|
||||
nonPublicDto := &SavePublicDashboardDTO{
|
||||
DashboardUid: nonPublicDashboard.Uid,
|
||||
OrgId: nonPublicDashboard.OrgId,
|
||||
PublicDashboard: &PublicDashboard{
|
||||
|
@ -115,7 +115,7 @@ func (pd *PublicDashboardServiceImpl) FindByDashboardUid(ctx context.Context, or
|
||||
|
||||
// Save is a helper method to persist the sharing config
|
||||
// to the database. It handles validations for sharing config and persistence
|
||||
func (pd *PublicDashboardServiceImpl) Save(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error) {
|
||||
func (pd *PublicDashboardServiceImpl) Save(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error) {
|
||||
// validate if the dashboard exists
|
||||
dashboard, err := pd.FindDashboard(ctx, dto.DashboardUid, u.OrgID)
|
||||
if err != nil {
|
||||
@ -193,7 +193,7 @@ func (pd *PublicDashboardServiceImpl) NewPublicDashboardAccessToken(ctx context.
|
||||
|
||||
// Called by Save this handles business logic
|
||||
// to generate token and calls create at the database layer
|
||||
func (pd *PublicDashboardServiceImpl) savePublicDashboard(ctx context.Context, dto *SavePublicDashboardConfigDTO) (string, error) {
|
||||
func (pd *PublicDashboardServiceImpl) savePublicDashboard(ctx context.Context, dto *SavePublicDashboardDTO) (string, error) {
|
||||
uid, err := pd.NewPublicDashboardUid(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -204,7 +204,7 @@ func (pd *PublicDashboardServiceImpl) savePublicDashboard(ctx context.Context, d
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd := SavePublicDashboardConfigCommand{
|
||||
cmd := SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
Uid: uid,
|
||||
DashboardUid: dto.DashboardUid,
|
||||
@ -228,8 +228,8 @@ func (pd *PublicDashboardServiceImpl) savePublicDashboard(ctx context.Context, d
|
||||
|
||||
// Called by Save this handles business logic for updating a
|
||||
// dashboard and calls update at the database layer
|
||||
func (pd *PublicDashboardServiceImpl) updatePublicDashboard(ctx context.Context, dto *SavePublicDashboardConfigDTO) (string, error) {
|
||||
cmd := SavePublicDashboardConfigCommand{
|
||||
func (pd *PublicDashboardServiceImpl) updatePublicDashboard(ctx context.Context, dto *SavePublicDashboardDTO) (string, error) {
|
||||
cmd := SavePublicDashboardCommand{
|
||||
PublicDashboard: PublicDashboard{
|
||||
Uid: dto.PublicDashboard.Uid,
|
||||
IsEnabled: dto.PublicDashboard.IsEnabled,
|
||||
|
@ -133,7 +133,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||
store: publicdashboardStore,
|
||||
}
|
||||
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
dto := &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 7,
|
||||
@ -179,7 +179,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||
store: publicdashboardStore,
|
||||
}
|
||||
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
dto := &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 7,
|
||||
@ -210,7 +210,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||
store: publicdashboardStore,
|
||||
}
|
||||
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
dto := &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 7,
|
||||
@ -246,7 +246,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||
store: publicDashboardStore,
|
||||
}
|
||||
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
dto := &SavePublicDashboardDTO{
|
||||
DashboardUid: "an-id",
|
||||
OrgId: 8,
|
||||
UserId: 7,
|
||||
@ -277,7 +277,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
store: publicdashboardStore,
|
||||
}
|
||||
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
dto := &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 7,
|
||||
@ -292,7 +292,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// attempt to overwrite settings
|
||||
dto = &SavePublicDashboardConfigDTO{
|
||||
dto = &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 8,
|
||||
@ -341,7 +341,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
store: publicdashboardStore,
|
||||
}
|
||||
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
dto := &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 7,
|
||||
@ -357,7 +357,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// attempt to overwrite settings
|
||||
dto = &SavePublicDashboardConfigDTO{
|
||||
dto = &SavePublicDashboardDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 8,
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
)
|
||||
|
||||
func ValidateSavePublicDashboard(dto *SavePublicDashboardConfigDTO, dashboard *models.Dashboard) error {
|
||||
func ValidateSavePublicDashboard(dto *SavePublicDashboardDTO, dashboard *models.Dashboard) error {
|
||||
if hasTemplateVariables(dashboard) {
|
||||
return ErrPublicDashboardHasTemplateVariables
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ func TestValidateSavePublicDashboard(t *testing.T) {
|
||||
}`)
|
||||
dashboardData, _ := simplejson.NewJson(templateVars)
|
||||
dashboard := models.NewDashboardFromJson(dashboardData)
|
||||
dto := &SavePublicDashboardConfigDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: nil}
|
||||
dto := &SavePublicDashboardDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: nil}
|
||||
|
||||
err := ValidateSavePublicDashboard(dto, dashboard)
|
||||
require.ErrorContains(t, err, ErrPublicDashboardHasTemplateVariables.Reason)
|
||||
@ -36,7 +36,7 @@ func TestValidateSavePublicDashboard(t *testing.T) {
|
||||
}`)
|
||||
dashboardData, _ := simplejson.NewJson(templateVars)
|
||||
dashboard := models.NewDashboardFromJson(dashboardData)
|
||||
dto := &SavePublicDashboardConfigDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: nil}
|
||||
dto := &SavePublicDashboardDTO{DashboardUid: "abc123", OrgId: 1, UserId: 1, PublicDashboard: nil}
|
||||
|
||||
err := ValidateSavePublicDashboard(dto, dashboard)
|
||||
require.NoError(t, err)
|
||||
|
Loading…
Reference in New Issue
Block a user