2021-10-27 06:13:59 -05:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2022-11-23 03:37:04 -06:00
|
|
|
"context"
|
2022-04-29 07:37:33 -05:00
|
|
|
"encoding/json"
|
2022-08-10 08:37:51 -05:00
|
|
|
"io"
|
2021-10-27 06:13:59 -05:00
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2022-08-11 08:37:31 -05:00
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
|
|
|
2022-05-17 13:52:22 -05:00
|
|
|
"github.com/stretchr/testify/assert"
|
2022-05-23 10:14:27 -05:00
|
|
|
"github.com/stretchr/testify/mock"
|
2022-05-17 13:52:22 -05:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2022-04-29 07:37:33 -05:00
|
|
|
"github.com/grafana/grafana/pkg/models"
|
2021-10-27 06:13:59 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
2022-05-17 13:52:22 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
2022-11-28 05:05:46 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/org"
|
2022-04-21 08:03:17 -05:00
|
|
|
pref "github.com/grafana/grafana/pkg/services/preference"
|
|
|
|
"github.com/grafana/grafana/pkg/services/preference/preftest"
|
2021-10-27 06:13:59 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2022-03-17 07:07:20 -05:00
|
|
|
getOrgPreferencesURL = "/api/org/preferences/"
|
|
|
|
putOrgPreferencesURL = "/api/org/preferences/"
|
|
|
|
patchOrgPreferencesUrl = "/api/org/preferences/"
|
|
|
|
patchUserPreferencesUrl = "/api/user/preferences/"
|
|
|
|
|
2022-04-29 07:37:33 -05:00
|
|
|
testUpdateOrgPreferencesCmd = `{ "theme": "light", "homeDashboardId": 1 }`
|
|
|
|
testPatchOrgPreferencesCmd = `{"navbar":{"savedItems":[{"id":"snapshots","text":"Snapshots","icon":"camera","url":"/dashboard/snapshots"}]}}`
|
|
|
|
testPatchOrgPreferencesCmdBad = `this is not json`
|
|
|
|
testPatchUserPreferencesCmd = `{"navbar":{"savedItems":[{"id":"snapshots","text":"Snapshots","icon":"camera","url":"/dashboard/snapshots"}]}}`
|
|
|
|
testPatchUserPreferencesCmdBad = `this is not json`
|
|
|
|
testUpdateOrgPreferencesWithHomeDashboardUIDCmd = `{ "theme": "light", "homeDashboardUID": "home"}`
|
2021-10-27 06:13:59 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestAPIEndpoint_GetCurrentOrgPreferences_LegacyAccessControl(t *testing.T) {
|
2022-08-11 08:37:31 -05:00
|
|
|
cfg := setting.NewCfg()
|
|
|
|
cfg.RBACEnabled = false
|
|
|
|
sc := setupHTTPServerWithCfg(t, true, cfg)
|
2022-05-23 10:14:27 -05:00
|
|
|
dashSvc := dashboards.NewFakeDashboardService(t)
|
|
|
|
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
|
|
|
|
q := args.Get(1).(*models.GetDashboardQuery)
|
|
|
|
q.Result = &models.Dashboard{Uid: "home", Id: 1}
|
|
|
|
}).Return(nil)
|
|
|
|
|
2022-07-06 13:42:39 -05:00
|
|
|
sc.hs.DashboardService = dashSvc
|
2022-04-29 07:37:33 -05:00
|
|
|
|
2022-04-21 08:03:17 -05:00
|
|
|
prefService := preftest.NewPreferenceServiceFake()
|
|
|
|
prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"}
|
|
|
|
sc.hs.preferenceService = prefService
|
2021-10-27 06:13:59 -05:00
|
|
|
|
2022-11-28 05:05:46 -06:00
|
|
|
_, err := sc.hs.orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "TestOrg", UserID: testUserID})
|
2021-10-27 06:13:59 -05:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
setInitCtxSignedInViewer(sc.initCtx)
|
|
|
|
t.Run("Viewer cannot get org preferences", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
|
|
|
|
assert.Equal(t, http.StatusForbidden, response.Code)
|
|
|
|
})
|
|
|
|
|
|
|
|
setInitCtxSignedInOrgAdmin(sc.initCtx)
|
|
|
|
t.Run("Org Admin can get org preferences", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
|
|
|
|
assert.Equal(t, http.StatusOK, response.Code)
|
2022-04-29 07:37:33 -05:00
|
|
|
var resp map[string]interface{}
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(response.Body)
|
2022-04-29 07:37:33 -05:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NoError(t, json.Unmarshal(b, &resp))
|
|
|
|
assert.Equal(t, "home", resp["homeDashboardUID"])
|
2021-10-27 06:13:59 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPIEndpoint_GetCurrentOrgPreferences_AccessControl(t *testing.T) {
|
2022-08-11 08:37:31 -05:00
|
|
|
sc := setupHTTPServer(t, true)
|
2021-10-27 06:13:59 -05:00
|
|
|
setInitCtxSignedInViewer(sc.initCtx)
|
|
|
|
|
2022-04-21 08:03:17 -05:00
|
|
|
prefService := preftest.NewPreferenceServiceFake()
|
|
|
|
prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"}
|
|
|
|
sc.hs.preferenceService = prefService
|
|
|
|
|
2022-11-28 05:05:46 -06:00
|
|
|
_, err := sc.hs.orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "TestOrg", UserID: testUserID})
|
2021-10-27 06:13:59 -05:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
t.Run("AccessControl allows getting org preferences with correct permissions", func(t *testing.T) {
|
2022-09-22 15:04:48 -05:00
|
|
|
setAccessControlPermissions(sc.acmock, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsPreferencesRead}}, sc.initCtx.OrgID)
|
2021-10-27 06:13:59 -05:00
|
|
|
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
|
|
|
|
assert.Equal(t, http.StatusOK, response.Code)
|
|
|
|
})
|
2021-11-17 03:12:28 -06:00
|
|
|
t.Run("AccessControl prevents getting org preferences with correct permissions in another org", func(t *testing.T) {
|
2022-09-22 15:04:48 -05:00
|
|
|
setAccessControlPermissions(sc.acmock, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsPreferencesRead}}, 2)
|
2021-10-27 06:13:59 -05:00
|
|
|
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
|
2021-11-17 03:12:28 -06:00
|
|
|
assert.Equal(t, http.StatusForbidden, response.Code)
|
2021-10-27 06:13:59 -05:00
|
|
|
})
|
|
|
|
t.Run("AccessControl prevents getting org preferences with incorrect permissions", func(t *testing.T) {
|
2022-08-11 06:28:55 -05:00
|
|
|
setAccessControlPermissions(sc.acmock, []accesscontrol.Permission{{Action: "orgs:invalid"}}, sc.initCtx.OrgID)
|
2021-10-27 06:13:59 -05:00
|
|
|
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
|
|
|
|
assert.Equal(t, http.StatusForbidden, response.Code)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPIEndpoint_PutCurrentOrgPreferences_LegacyAccessControl(t *testing.T) {
|
2022-08-11 08:37:31 -05:00
|
|
|
cfg := setting.NewCfg()
|
|
|
|
cfg.RBACEnabled = false
|
|
|
|
sc := setupHTTPServerWithCfg(t, true, cfg)
|
2021-10-27 06:13:59 -05:00
|
|
|
|
2022-11-28 05:05:46 -06:00
|
|
|
_, err := sc.hs.orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "TestOrg", UserID: testUserID})
|
2021-10-27 06:13:59 -05:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
setInitCtxSignedInViewer(sc.initCtx)
|
|
|
|
input := strings.NewReader(testUpdateOrgPreferencesCmd)
|
|
|
|
t.Run("Viewer cannot update org preferences", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
|
|
|
|
assert.Equal(t, http.StatusForbidden, response.Code)
|
|
|
|
})
|
|
|
|
|
|
|
|
setInitCtxSignedInOrgAdmin(sc.initCtx)
|
|
|
|
input = strings.NewReader(testUpdateOrgPreferencesCmd)
|
|
|
|
t.Run("Org Admin can update org preferences", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
|
|
|
|
assert.Equal(t, http.StatusOK, response.Code)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPIEndpoint_PutCurrentOrgPreferences_AccessControl(t *testing.T) {
|
2022-08-11 08:37:31 -05:00
|
|
|
sc := setupHTTPServer(t, true)
|
2021-10-27 06:13:59 -05:00
|
|
|
setInitCtxSignedInViewer(sc.initCtx)
|
|
|
|
|
2022-11-28 05:05:46 -06:00
|
|
|
_, err := sc.hs.orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "TestOrg", UserID: testUserID})
|
2021-10-27 06:13:59 -05:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
input := strings.NewReader(testUpdateOrgPreferencesCmd)
|
|
|
|
t.Run("AccessControl allows updating org preferences with correct permissions", func(t *testing.T) {
|
2022-09-22 15:04:48 -05:00
|
|
|
setAccessControlPermissions(sc.acmock, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsPreferencesWrite}}, sc.initCtx.OrgID)
|
2021-10-27 06:13:59 -05:00
|
|
|
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
|
|
|
|
assert.Equal(t, http.StatusOK, response.Code)
|
|
|
|
})
|
|
|
|
|
|
|
|
input = strings.NewReader(testUpdateOrgPreferencesCmd)
|
2021-11-17 03:12:28 -06:00
|
|
|
t.Run("AccessControl prevents updating org preferences with correct permissions in another org", func(t *testing.T) {
|
2022-09-22 15:04:48 -05:00
|
|
|
setAccessControlPermissions(sc.acmock, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsPreferencesWrite}}, 2)
|
2021-10-27 06:13:59 -05:00
|
|
|
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
|
2021-11-17 03:12:28 -06:00
|
|
|
assert.Equal(t, http.StatusForbidden, response.Code)
|
2021-10-27 06:13:59 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
input = strings.NewReader(testUpdateOrgPreferencesCmd)
|
|
|
|
t.Run("AccessControl prevents updating org preferences with incorrect permissions", func(t *testing.T) {
|
2022-08-11 06:28:55 -05:00
|
|
|
setAccessControlPermissions(sc.acmock, []accesscontrol.Permission{{Action: "orgs:invalid"}}, sc.initCtx.OrgID)
|
2021-10-27 06:13:59 -05:00
|
|
|
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
|
|
|
|
assert.Equal(t, http.StatusForbidden, response.Code)
|
|
|
|
})
|
|
|
|
}
|
2022-03-17 07:07:20 -05:00
|
|
|
|
|
|
|
func TestAPIEndpoint_PatchUserPreferences(t *testing.T) {
|
2022-08-11 08:37:31 -05:00
|
|
|
cfg := setting.NewCfg()
|
|
|
|
cfg.RBACEnabled = false
|
|
|
|
sc := setupHTTPServerWithCfg(t, true, cfg)
|
2022-03-17 07:07:20 -05:00
|
|
|
|
2022-11-28 05:05:46 -06:00
|
|
|
_, err := sc.hs.orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "TestOrg", UserID: testUserID})
|
2022-03-17 07:07:20 -05:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
setInitCtxSignedInOrgAdmin(sc.initCtx)
|
|
|
|
input := strings.NewReader(testPatchUserPreferencesCmd)
|
|
|
|
t.Run("Returns 200 on success", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodPatch, patchUserPreferencesUrl, input, t)
|
|
|
|
assert.Equal(t, http.StatusOK, response.Code)
|
|
|
|
})
|
|
|
|
|
|
|
|
input = strings.NewReader(testPatchUserPreferencesCmdBad)
|
|
|
|
t.Run("Returns 400 with bad data", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodPut, patchUserPreferencesUrl, input, t)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, response.Code)
|
|
|
|
})
|
2022-04-29 07:37:33 -05:00
|
|
|
input = strings.NewReader(testUpdateOrgPreferencesWithHomeDashboardUIDCmd)
|
2022-05-23 10:14:27 -05:00
|
|
|
dashSvc := dashboards.NewFakeDashboardService(t)
|
|
|
|
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
|
|
|
|
q := args.Get(1).(*models.GetDashboardQuery)
|
|
|
|
q.Result = &models.Dashboard{Uid: "home", Id: 1}
|
|
|
|
}).Return(nil)
|
2022-07-06 13:42:39 -05:00
|
|
|
sc.hs.DashboardService = dashSvc
|
2022-04-29 07:37:33 -05:00
|
|
|
t.Run("Returns 200 on success", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodPatch, patchUserPreferencesUrl, input, t)
|
|
|
|
assert.Equal(t, http.StatusOK, response.Code)
|
|
|
|
})
|
2022-03-17 07:07:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPIEndpoint_PatchOrgPreferences(t *testing.T) {
|
2022-08-11 08:37:31 -05:00
|
|
|
cfg := setting.NewCfg()
|
|
|
|
cfg.RBACEnabled = false
|
|
|
|
sc := setupHTTPServerWithCfg(t, true, cfg)
|
2022-03-17 07:07:20 -05:00
|
|
|
|
2022-11-28 05:05:46 -06:00
|
|
|
_, err := sc.hs.orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "TestOrg", UserID: testUserID})
|
2022-03-17 07:07:20 -05:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
setInitCtxSignedInOrgAdmin(sc.initCtx)
|
|
|
|
input := strings.NewReader(testPatchOrgPreferencesCmd)
|
|
|
|
t.Run("Returns 200 on success", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodPatch, patchOrgPreferencesUrl, input, t)
|
|
|
|
assert.Equal(t, http.StatusOK, response.Code)
|
|
|
|
})
|
|
|
|
|
|
|
|
input = strings.NewReader(testPatchOrgPreferencesCmdBad)
|
|
|
|
t.Run("Returns 400 with bad data", func(t *testing.T) {
|
|
|
|
response := callAPI(sc.server, http.MethodPut, patchOrgPreferencesUrl, input, t)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, response.Code)
|
|
|
|
})
|
|
|
|
}
|