PublicDashboards: Accept uid to pubdash creation (#73956)

* accept uid to pubdash creation

* add accesstoken back

* add uid validation unit tests

* unit test for create pubdash with uid

* update err declaration

* remove white space

* add comment

* remove trailing spaces

* remove space

* suggested changes
This commit is contained in:
Lucy Chen 2023-08-29 17:25:07 -04:00 committed by GitHub
parent dfba94e052
commit a39d1e278e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 121 additions and 4 deletions

View File

@ -149,6 +149,12 @@ func (api *Api) CreatePublicDashboard(c *contextmodel.ReqContext) response.Respo
return response.Err(ErrBadRequest.Errorf("CreatePublicDashboard: bad request data %v", err))
}
//validate uid
uid := pdDTO.Uid
if uid != "" && !validation.IsValidShortUID(uid) {
return response.Err(ErrInvalidUid.Errorf("CreatePublicDashboard: invalid Uid %s", uid))
}
// Always set the orgID and userID from the session
dto := &SavePublicDashboardDTO{
UserId: c.UserID,

View File

@ -391,6 +391,7 @@ func TestApiCreatePublicDashboard(t *testing.T) {
SaveDashboardErr error
User *user.SignedInUser
ShouldCallService bool
JsonBody string
}{
{
Name: "returns 500 when not persisted",
@ -399,6 +400,7 @@ func TestApiCreatePublicDashboard(t *testing.T) {
SaveDashboardErr: ErrInternalServerError.Errorf(""),
User: userAdmin,
ShouldCallService: true,
JsonBody: `{ "isPublic": true }`,
},
{
Name: "returns 404 when dashboard not found",
@ -407,6 +409,7 @@ func TestApiCreatePublicDashboard(t *testing.T) {
SaveDashboardErr: ErrDashboardNotFound.Errorf(""),
User: userAdmin,
ShouldCallService: true,
JsonBody: `{ "isPublic": true }`,
},
{
Name: "returns 200 when update persists RBAC on",
@ -416,6 +419,7 @@ func TestApiCreatePublicDashboard(t *testing.T) {
SaveDashboardErr: nil,
User: userAdmin,
ShouldCallService: true,
JsonBody: `{ "isPublic": true }`,
},
{
Name: "returns 403 when no permissions RBAC on",
@ -424,6 +428,25 @@ func TestApiCreatePublicDashboard(t *testing.T) {
SaveDashboardErr: nil,
User: userNoRBACPerms,
ShouldCallService: false,
JsonBody: `{ "isPublic": true }`,
},
{
Name: "returns 400 when uid is invalid",
ExpectedHttpResponse: http.StatusBadRequest,
publicDashboard: nil,
SaveDashboardErr: nil,
User: userAdmin,
ShouldCallService: false,
JsonBody: `{ "uid": "*", "isEnabled": true }`,
},
{
Name: "returns 200 when uid is valid",
ExpectedHttpResponse: http.StatusOK,
publicDashboard: &PublicDashboard{IsEnabled: true},
SaveDashboardErr: nil,
User: userAdmin,
ShouldCallService: true,
JsonBody: `{ "uid": "123abc", "isEnabled": true}`,
},
}
@ -452,7 +475,7 @@ func TestApiCreatePublicDashboard(t *testing.T) {
testServer,
http.MethodPost,
"/api/dashboards/uid/1/public-dashboards",
strings.NewReader(`{ "isPublic": true }`),
strings.NewReader(test.JsonBody),
t,
)

View File

@ -21,6 +21,7 @@ var (
ErrInvalidTimeRange = errutil.BadRequest("publicdashboards.invalidTimeRange", errutil.WithPublicMessage("Invalid time range"))
ErrInvalidShareType = errutil.BadRequest("publicdashboards.invalidShareType", errutil.WithPublicMessage("Invalid share type"))
ErrDashboardIsPublic = errutil.BadRequest("publicdashboards.dashboardIsPublic", errutil.WithPublicMessage("Dashboard is already public"))
ErrPublicDashboardUidExists = errutil.BadRequest("publicdashboards.uidExists", errutil.WithPublicMessage("Public Dashboard Uid exists"))
ErrPublicDashboardNotEnabled = errutil.Forbidden("publicdashboards.notEnabled", errutil.WithPublicMessage("Public dashboard paused"))
)

View File

@ -56,6 +56,7 @@ type PublicDashboard struct {
}
type PublicDashboardDTO struct {
Uid string `json:"uid"`
TimeSelectionEnabled *bool `json:"timeSelectionEnabled"`
IsEnabled *bool `json:"isEnabled"`
AnnotationsEnabled *bool `json:"annotationsEnabled"`

View File

@ -428,9 +428,19 @@ func GenerateAccessToken() (string, error) {
}
func (pd *PublicDashboardServiceImpl) newCreatePublicDashboard(ctx context.Context, dto *SavePublicDashboardDTO) (*PublicDashboard, error) {
uid, err := pd.NewPublicDashboardUid(ctx)
if err != nil {
return nil, err
//Check if uid already exists, if none then auto generate
existingPubdash, _ := pd.store.Find(ctx, dto.PublicDashboard.Uid)
if existingPubdash != nil {
return nil, ErrPublicDashboardUidExists.Errorf("Create: public dashboard uid %s already exists", dto.PublicDashboard.Uid)
}
var err error
uid := dto.PublicDashboard.Uid
if dto.PublicDashboard.Uid == "" {
uid, err = pd.NewPublicDashboardUid(ctx)
if err != nil {
return nil, err
}
}
accessToken, err := pd.NewPublicDashboardAccessToken(ctx)

View File

@ -780,6 +780,82 @@ func TestCreatePublicDashboard(t *testing.T) {
assert.Equal(t, dashboard.OrgID, pubdash.OrgId)
})
t.Run("Throws an error when given pubdash uid already exists", func(t *testing.T) {
dashboard := dashboards.NewDashboard("testDashie")
pubdash := &PublicDashboard{
Uid: "ExistingUid",
IsEnabled: true,
AnnotationsEnabled: false,
DashboardUid: "NOTTHESAME",
OrgId: dashboard.OrgID,
TimeSettings: timeSettings,
}
publicDashboardStore := &FakePublicDashboardStore{}
publicDashboardStore.On("FindDashboard", mock.Anything, mock.Anything, mock.Anything).Return(dashboard, nil)
publicDashboardStore.On("Find", mock.Anything, "ExistingUid").Return(pubdash, nil)
publicDashboardStore.On("FindByDashboardUid", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrPublicDashboardNotFound.Errorf(""))
serviceWrapper := ProvideServiceWrapper(publicDashboardStore)
service := &PublicDashboardServiceImpl{
log: log.New("test.logger"),
store: publicDashboardStore,
serviceWrapper: serviceWrapper,
}
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: "an-id",
OrgID: dashboard.OrgID,
UserId: 7,
PublicDashboard: &PublicDashboardDTO{
Uid: "ExistingUid",
IsEnabled: &isEnabled,
},
}
_, err := service.Create(context.Background(), SignedInUser, dto)
require.Error(t, err)
require.Equal(t, err, ErrPublicDashboardUidExists.Errorf("Create: public dashboard uid %s already exists", dto.PublicDashboard.Uid))
})
t.Run("Create public dashboard with given pubdash uid", func(t *testing.T) {
sqlStore := db.InitTestDB(t)
quotaService := quotatest.New(false, nil)
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
require.NoError(t, err)
publicdashboardStore := database.ProvideStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures())
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
serviceWrapper := ProvideServiceWrapper(publicdashboardStore)
service := &PublicDashboardServiceImpl{
log: log.New("test.logger"),
store: publicdashboardStore,
serviceWrapper: serviceWrapper,
}
isEnabled := true
dto := &SavePublicDashboardDTO{
DashboardUid: dashboard.UID,
UserId: 7,
OrgID: dashboard.OrgID,
PublicDashboard: &PublicDashboardDTO{
Uid: "GivenUid",
IsEnabled: &isEnabled,
},
}
_, err = service.Create(context.Background(), SignedInUser, dto)
require.NoError(t, err)
pubdash, err := service.FindByDashboardUid(context.Background(), dashboard.OrgID, dashboard.UID)
require.NoError(t, err)
assert.Equal(t, dto.PublicDashboard.Uid, pubdash.Uid)
})
t.Run("Throws an error when pubdash with generated access token already exists", func(t *testing.T) {
dashboard := dashboards.NewDashboard("testDashie")
pubdash := &PublicDashboard{