mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Add context to org users (#39526)
* Add context to org users * Fix go lint * Roll back xorm refactor * Use WithTransactionalDbSession * Update sqlstore.go Fix typo * Update org_users.go Fix typo
This commit is contained in:
parent
60f5bceda5
commit
65ebb04cf3
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -45,6 +46,10 @@ func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url
|
||||
return sc.handlerFunc(sc.context)
|
||||
}
|
||||
|
||||
if sc.handlerFuncCtx != nil {
|
||||
return sc.handlerFuncCtx(context.Background(), sc.context)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@ -70,6 +75,10 @@ func anonymousUserScenario(t *testing.T, desc string, method string, url string,
|
||||
return sc.handlerFunc(sc.context)
|
||||
}
|
||||
|
||||
if sc.handlerFuncCtx != nil {
|
||||
return sc.handlerFuncCtx(context.Background(), sc.context)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@ -109,7 +118,6 @@ func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
sc.req = req
|
||||
|
||||
return sc
|
||||
}
|
||||
|
||||
@ -140,6 +148,7 @@ type scenarioContext struct {
|
||||
context *models.ReqContext
|
||||
resp *httptest.ResponseRecorder
|
||||
handlerFunc handlerFunc
|
||||
handlerFuncCtx handlerFuncCtx
|
||||
defaultHandler macaron.Handler
|
||||
req *http.Request
|
||||
url string
|
||||
@ -152,6 +161,7 @@ func (sc *scenarioContext) exec() {
|
||||
|
||||
type scenarioFunc func(c *scenarioContext)
|
||||
type handlerFunc func(c *models.ReqContext) response.Response
|
||||
type handlerFuncCtx func(ctx context.Context, c *models.ReqContext) response.Response
|
||||
|
||||
func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHandler {
|
||||
t.Helper()
|
||||
|
@ -1,35 +1,35 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
// POST /api/org/users
|
||||
func AddOrgUserToCurrentOrg(c *models.ReqContext, cmd models.AddOrgUserCommand) response.Response {
|
||||
cmd.OrgId = c.OrgId
|
||||
return addOrgUserHelper(cmd)
|
||||
return addOrgUserHelper(c.Req.Context(), cmd)
|
||||
}
|
||||
|
||||
// POST /api/orgs/:orgId/users
|
||||
func AddOrgUser(c *models.ReqContext, cmd models.AddOrgUserCommand) response.Response {
|
||||
cmd.OrgId = c.ParamsInt64(":orgId")
|
||||
return addOrgUserHelper(cmd)
|
||||
return addOrgUserHelper(c.Req.Context(), cmd)
|
||||
}
|
||||
|
||||
func addOrgUserHelper(cmd models.AddOrgUserCommand) response.Response {
|
||||
func addOrgUserHelper(ctx context.Context, cmd models.AddOrgUserCommand) response.Response {
|
||||
if !cmd.Role.IsValid() {
|
||||
return response.Error(400, "Invalid role specified", nil)
|
||||
}
|
||||
|
||||
userQuery := models.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
|
||||
err := bus.Dispatch(&userQuery)
|
||||
err := bus.DispatchCtx(ctx, &userQuery)
|
||||
if err != nil {
|
||||
return response.Error(404, "User not found", nil)
|
||||
}
|
||||
@ -38,7 +38,7 @@ func addOrgUserHelper(cmd models.AddOrgUserCommand) response.Response {
|
||||
|
||||
cmd.UserId = userToAdd.Id
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
if err := bus.DispatchCtx(ctx, &cmd); err != nil {
|
||||
if errors.Is(err, models.ErrOrgUserAlreadyAdded) {
|
||||
return response.JSON(409, util.DynMap{
|
||||
"message": "User is already member of this organization",
|
||||
@ -56,7 +56,7 @@ func addOrgUserHelper(cmd models.AddOrgUserCommand) response.Response {
|
||||
|
||||
// GET /api/org/users
|
||||
func (hs *HTTPServer) GetOrgUsersForCurrentOrg(c *models.ReqContext) response.Response {
|
||||
result, err := hs.getOrgUsersHelper(&models.GetOrgUsersQuery{
|
||||
result, err := hs.getOrgUsersHelper(c.Req.Context(), &models.GetOrgUsersQuery{
|
||||
OrgId: c.OrgId,
|
||||
Query: c.Query("query"),
|
||||
Limit: c.QueryInt("limit"),
|
||||
@ -71,7 +71,7 @@ func (hs *HTTPServer) GetOrgUsersForCurrentOrg(c *models.ReqContext) response.Re
|
||||
|
||||
// GET /api/org/users/lookup
|
||||
func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) response.Response {
|
||||
orgUsers, err := hs.getOrgUsersHelper(&models.GetOrgUsersQuery{
|
||||
orgUsers, err := hs.getOrgUsersHelper(c.Req.Context(), &models.GetOrgUsersQuery{
|
||||
OrgId: c.OrgId,
|
||||
Query: c.Query("query"),
|
||||
Limit: c.QueryInt("limit"),
|
||||
@ -96,7 +96,7 @@ func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) respo
|
||||
|
||||
// GET /api/orgs/:orgId/users
|
||||
func (hs *HTTPServer) GetOrgUsers(c *models.ReqContext) response.Response {
|
||||
result, err := hs.getOrgUsersHelper(&models.GetOrgUsersQuery{
|
||||
result, err := hs.getOrgUsersHelper(c.Req.Context(), &models.GetOrgUsersQuery{
|
||||
OrgId: c.ParamsInt64(":orgId"),
|
||||
Query: "",
|
||||
Limit: 0,
|
||||
@ -109,8 +109,8 @@ func (hs *HTTPServer) GetOrgUsers(c *models.ReqContext) response.Response {
|
||||
return response.JSON(200, result)
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getOrgUsersHelper(query *models.GetOrgUsersQuery, signedInUser *models.SignedInUser) ([]*models.OrgUserDTO, error) {
|
||||
if err := sqlstore.GetOrgUsers(query); err != nil {
|
||||
func (hs *HTTPServer) getOrgUsersHelper(ctx context.Context, query *models.GetOrgUsersQuery, signedInUser *models.SignedInUser) ([]*models.OrgUserDTO, error) {
|
||||
if err := hs.SQLStore.GetOrgUsers(ctx, query); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -129,7 +129,7 @@ func (hs *HTTPServer) getOrgUsersHelper(query *models.GetOrgUsersQuery, signedIn
|
||||
|
||||
// SearchOrgUsersWithPaging is an HTTP handler to search for org users with paging.
|
||||
// GET /api/org/users/search
|
||||
func (hs *HTTPServer) SearchOrgUsersWithPaging(c *models.ReqContext) response.Response {
|
||||
func (hs *HTTPServer) SearchOrgUsersWithPaging(ctx context.Context, c *models.ReqContext) response.Response {
|
||||
perPage := c.QueryInt("perpage")
|
||||
if perPage <= 0 {
|
||||
perPage = 1000
|
||||
@ -147,7 +147,7 @@ func (hs *HTTPServer) SearchOrgUsersWithPaging(c *models.ReqContext) response.Re
|
||||
Page: page,
|
||||
}
|
||||
|
||||
if err := hs.SQLStore.SearchOrgUsers(query); err != nil {
|
||||
if err := hs.SQLStore.SearchOrgUsers(ctx, query); err != nil {
|
||||
return response.Error(500, "Failed to get users for current organization", err)
|
||||
}
|
||||
|
||||
@ -172,21 +172,21 @@ func (hs *HTTPServer) SearchOrgUsersWithPaging(c *models.ReqContext) response.Re
|
||||
func UpdateOrgUserForCurrentOrg(c *models.ReqContext, cmd models.UpdateOrgUserCommand) response.Response {
|
||||
cmd.OrgId = c.OrgId
|
||||
cmd.UserId = c.ParamsInt64(":userId")
|
||||
return updateOrgUserHelper(cmd)
|
||||
return updateOrgUserHelper(c.Req.Context(), cmd)
|
||||
}
|
||||
|
||||
// PATCH /api/orgs/:orgId/users/:userId
|
||||
func UpdateOrgUser(c *models.ReqContext, cmd models.UpdateOrgUserCommand) response.Response {
|
||||
cmd.OrgId = c.ParamsInt64(":orgId")
|
||||
cmd.UserId = c.ParamsInt64(":userId")
|
||||
return updateOrgUserHelper(cmd)
|
||||
return updateOrgUserHelper(c.Req.Context(), cmd)
|
||||
}
|
||||
|
||||
func updateOrgUserHelper(cmd models.UpdateOrgUserCommand) response.Response {
|
||||
func updateOrgUserHelper(ctx context.Context, cmd models.UpdateOrgUserCommand) response.Response {
|
||||
if !cmd.Role.IsValid() {
|
||||
return response.Error(400, "Invalid role specified", nil)
|
||||
}
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
if err := bus.DispatchCtx(ctx, &cmd); err != nil {
|
||||
if errors.Is(err, models.ErrLastOrgAdmin) {
|
||||
return response.Error(400, "Cannot change role so that there is no organization admin left", nil)
|
||||
}
|
||||
@ -198,7 +198,7 @@ func updateOrgUserHelper(cmd models.UpdateOrgUserCommand) response.Response {
|
||||
|
||||
// DELETE /api/org/users/:userId
|
||||
func RemoveOrgUserForCurrentOrg(c *models.ReqContext) response.Response {
|
||||
return removeOrgUserHelper(&models.RemoveOrgUserCommand{
|
||||
return removeOrgUserHelper(c.Req.Context(), &models.RemoveOrgUserCommand{
|
||||
UserId: c.ParamsInt64(":userId"),
|
||||
OrgId: c.OrgId,
|
||||
ShouldDeleteOrphanedUser: true,
|
||||
@ -207,14 +207,14 @@ func RemoveOrgUserForCurrentOrg(c *models.ReqContext) response.Response {
|
||||
|
||||
// DELETE /api/orgs/:orgId/users/:userId
|
||||
func RemoveOrgUser(c *models.ReqContext) response.Response {
|
||||
return removeOrgUserHelper(&models.RemoveOrgUserCommand{
|
||||
return removeOrgUserHelper(c.Req.Context(), &models.RemoveOrgUserCommand{
|
||||
UserId: c.ParamsInt64(":userId"),
|
||||
OrgId: c.ParamsInt64(":orgId"),
|
||||
})
|
||||
}
|
||||
|
||||
func removeOrgUserHelper(cmd *models.RemoveOrgUserCommand) response.Response {
|
||||
if err := bus.Dispatch(cmd); err != nil {
|
||||
func removeOrgUserHelper(ctx context.Context, cmd *models.RemoveOrgUserCommand) response.Response {
|
||||
if err := bus.DispatchCtx(ctx, cmd); err != nil {
|
||||
if errors.Is(err, models.ErrLastOrgAdmin) {
|
||||
return response.Error(400, "Cannot remove last organization admin", nil)
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
|
||||
hs := &HTTPServer{Cfg: settings}
|
||||
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
hs.SQLStore = sqlStore
|
||||
|
||||
loggedInUserScenario(t, "When calling GET on", "api/org/users", func(sc *scenarioContext) {
|
||||
setUpGetOrgUsersDB(t, sqlStore)
|
||||
@ -56,7 +57,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
|
||||
loggedInUserScenario(t, "When calling GET on", "api/org/users/search", func(sc *scenarioContext) {
|
||||
setUpGetOrgUsersDB(t, sqlStore)
|
||||
|
||||
sc.handlerFunc = hs.SearchOrgUsersWithPaging
|
||||
sc.handlerFuncCtx = hs.SearchOrgUsersWithPaging
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
require.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
@ -74,7 +75,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
|
||||
loggedInUserScenario(t, "When calling GET with page and limit query parameters on", "api/org/users/search", func(sc *scenarioContext) {
|
||||
setUpGetOrgUsersDB(t, sqlStore)
|
||||
|
||||
sc.handlerFunc = hs.SearchOrgUsersWithPaging
|
||||
sc.handlerFuncCtx = hs.SearchOrgUsersWithPaging
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "2", "page": "2"}).exec()
|
||||
|
||||
require.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
@ -254,7 +255,6 @@ func TestOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
||||
permissions: []*accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersRead, Scope: accesscontrol.ScopeUsersAll}},
|
||||
},
|
||||
{
|
||||
|
||||
expectedCode: http.StatusForbidden,
|
||||
desc: "UsersLookupGet should return 403 for user without required permissions",
|
||||
url: "/api/org/users/lookup",
|
||||
|
@ -11,14 +11,14 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAccountDataAccess(t *testing.T) {
|
||||
Convey("Testing Account DB Access", t, func() {
|
||||
t.Run("Testing Account DB Access", func(t *testing.T) {
|
||||
sqlStore := InitTestDB(t)
|
||||
|
||||
Convey("Given we have organizations, we can query them by IDs", func() {
|
||||
t.Run("Given we have organizations, we can query them by IDs", func(t *testing.T) {
|
||||
var err error
|
||||
var cmd *models.CreateOrgCommand
|
||||
ids := []int64{}
|
||||
@ -26,7 +26,7 @@ func TestAccountDataAccess(t *testing.T) {
|
||||
for i := 1; i < 4; i++ {
|
||||
cmd = &models.CreateOrgCommand{Name: fmt.Sprint("Org #", i)}
|
||||
err = CreateOrg(cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
ids = append(ids, cmd.Result.Id)
|
||||
}
|
||||
@ -34,69 +34,71 @@ func TestAccountDataAccess(t *testing.T) {
|
||||
query := &models.SearchOrgsQuery{Ids: ids}
|
||||
err = SearchOrgs(query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 3)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result), 3)
|
||||
})
|
||||
|
||||
Convey("Given we have organizations, we can limit and paginate search", func() {
|
||||
t.Run("Given we have organizations, we can limit and paginate search", func(t *testing.T) {
|
||||
sqlStore = InitTestDB(t)
|
||||
for i := 1; i < 4; i++ {
|
||||
cmd := &models.CreateOrgCommand{Name: fmt.Sprint("Org #", i)}
|
||||
err := CreateOrg(cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
Convey("Should be able to search with defaults", func() {
|
||||
t.Run("Should be able to search with defaults", func(t *testing.T) {
|
||||
query := &models.SearchOrgsQuery{}
|
||||
err := SearchOrgs(query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 3)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result), 3)
|
||||
})
|
||||
|
||||
Convey("Should be able to limit search", func() {
|
||||
t.Run("Should be able to limit search", func(t *testing.T) {
|
||||
query := &models.SearchOrgsQuery{Limit: 1}
|
||||
err := SearchOrgs(query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result), 1)
|
||||
})
|
||||
|
||||
Convey("Should be able to limit and paginate search", func() {
|
||||
t.Run("Should be able to limit and paginate search", func(t *testing.T) {
|
||||
query := &models.SearchOrgsQuery{Limit: 2, Page: 1}
|
||||
err := SearchOrgs(query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result), 1)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given single org mode", func() {
|
||||
t.Run("Given single org mode", func(t *testing.T) {
|
||||
setting.AutoAssignOrg = true
|
||||
setting.AutoAssignOrgId = 1
|
||||
setting.AutoAssignOrgRole = "Viewer"
|
||||
|
||||
Convey("Users should be added to default organization", func() {
|
||||
t.Run("Users should be added to default organization", func(t *testing.T) {
|
||||
ac1cmd := models.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"}
|
||||
ac2cmd := models.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name"}
|
||||
|
||||
ac1, err := sqlStore.CreateUser(context.Background(), ac1cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
ac2, err := sqlStore.CreateUser(context.Background(), ac2cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
q1 := models.GetUserOrgListQuery{UserId: ac1.Id}
|
||||
q2 := models.GetUserOrgListQuery{UserId: ac2.Id}
|
||||
err = GetUserOrgList(&q1)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
err = GetUserOrgList(&q2)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
So(q1.Result[0].OrgId, ShouldEqual, q2.Result[0].OrgId)
|
||||
So(q1.Result[0].Role, ShouldEqual, "Viewer")
|
||||
require.Equal(t, q1.Result[0].OrgId, q2.Result[0].OrgId)
|
||||
require.Equal(t, string(q1.Result[0].Role), "Viewer")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given single org and 2 users inserted", func() {
|
||||
t.Run("Given single org and 2 users inserted", func(t *testing.T) {
|
||||
sqlStore = InitTestDB(t)
|
||||
setting.AutoAssignOrg = true
|
||||
setting.AutoAssignOrgId = 1
|
||||
setting.AutoAssignOrgRole = "Viewer"
|
||||
@ -105,204 +107,206 @@ func TestAccountDataAccess(t *testing.T) {
|
||||
ac2cmd := models.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name"}
|
||||
|
||||
ac1, err := sqlStore.CreateUser(context.Background(), ac1cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
_, err = sqlStore.CreateUser(context.Background(), ac2cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
Convey("Can get organization users paginated with query", func() {
|
||||
t.Run("Can get organization users paginated with query", func(t *testing.T) {
|
||||
query := models.SearchOrgUsersQuery{
|
||||
OrgID: ac1.OrgId,
|
||||
Page: 1,
|
||||
}
|
||||
err = sqlStore.SearchOrgUsers(&query)
|
||||
err = sqlStore.SearchOrgUsers(context.Background(), &query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result.OrgUsers), ShouldEqual, 2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result.OrgUsers), 2)
|
||||
})
|
||||
|
||||
Convey("Can get organization users paginated and limited", func() {
|
||||
t.Run("Can get organization users paginated and limited", func(t *testing.T) {
|
||||
query := models.SearchOrgUsersQuery{
|
||||
OrgID: ac1.OrgId,
|
||||
Limit: 1,
|
||||
Page: 1,
|
||||
}
|
||||
err = sqlStore.SearchOrgUsers(&query)
|
||||
err = sqlStore.SearchOrgUsers(context.Background(), &query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result.OrgUsers), ShouldEqual, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result.OrgUsers), 1)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given two saved users", func() {
|
||||
t.Run("Given two saved users", func(t *testing.T) {
|
||||
sqlStore = InitTestDB(t)
|
||||
setting.AutoAssignOrg = false
|
||||
|
||||
ac1cmd := models.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"}
|
||||
ac2cmd := models.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true}
|
||||
|
||||
ac1, err := sqlStore.CreateUser(context.Background(), ac1cmd)
|
||||
require.NoError(t, err)
|
||||
ac2, err := sqlStore.CreateUser(context.Background(), ac2cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
Convey("Should be able to read user info projection", func() {
|
||||
t.Run("Should be able to read user info projection", func(t *testing.T) {
|
||||
query := models.GetUserProfileQuery{UserId: ac1.Id}
|
||||
err = GetUserProfile(&query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(query.Result.Email, ShouldEqual, "ac1@test.com")
|
||||
So(query.Result.Login, ShouldEqual, "ac1")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, query.Result.Email, "ac1@test.com")
|
||||
require.Equal(t, query.Result.Login, "ac1")
|
||||
})
|
||||
|
||||
Convey("Can search users", func() {
|
||||
t.Run("Can search users", func(t *testing.T) {
|
||||
query := models.SearchUsersQuery{Query: ""}
|
||||
err := SearchUsers(&query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(query.Result.Users[0].Email, ShouldEqual, "ac1@test.com")
|
||||
So(query.Result.Users[1].Email, ShouldEqual, "ac2@test.com")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, query.Result.Users[0].Email, "ac1@test.com")
|
||||
require.Equal(t, query.Result.Users[1].Email, "ac2@test.com")
|
||||
})
|
||||
|
||||
Convey("Given an added org user", func() {
|
||||
t.Run("Given an added org user", func(t *testing.T) {
|
||||
cmd := models.AddOrgUserCommand{
|
||||
OrgId: ac1.OrgId,
|
||||
UserId: ac2.Id,
|
||||
Role: models.ROLE_VIEWER,
|
||||
}
|
||||
|
||||
err := AddOrgUser(&cmd)
|
||||
Convey("Should have been saved without error", func() {
|
||||
So(err, ShouldBeNil)
|
||||
err := sqlStore.AddOrgUser(context.Background(), &cmd)
|
||||
t.Run("Should have been saved without error", func(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
Convey("Can update org user role", func() {
|
||||
t.Run("Can update org user role", func(t *testing.T) {
|
||||
updateCmd := models.UpdateOrgUserCommand{OrgId: ac1.OrgId, UserId: ac2.Id, Role: models.ROLE_ADMIN}
|
||||
err = UpdateOrgUser(&updateCmd)
|
||||
So(err, ShouldBeNil)
|
||||
err = sqlStore.UpdateOrgUser(context.Background(), &updateCmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
orgUsersQuery := models.GetOrgUsersQuery{OrgId: ac1.OrgId}
|
||||
err = GetOrgUsers(&orgUsersQuery)
|
||||
So(err, ShouldBeNil)
|
||||
err = sqlStore.GetOrgUsers(context.Background(), &orgUsersQuery)
|
||||
require.NoError(t, err)
|
||||
|
||||
So(orgUsersQuery.Result[1].Role, ShouldEqual, models.ROLE_ADMIN)
|
||||
require.EqualValues(t, orgUsersQuery.Result[1].Role, models.ROLE_ADMIN)
|
||||
})
|
||||
|
||||
Convey("Can get logged in user projection", func() {
|
||||
t.Run("Can get logged in user projection", func(t *testing.T) {
|
||||
query := models.GetSignedInUserQuery{UserId: ac2.Id}
|
||||
err := GetSignedInUser(context.Background(), &query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(query.Result.Email, ShouldEqual, "ac2@test.com")
|
||||
So(query.Result.OrgId, ShouldEqual, ac2.OrgId)
|
||||
So(query.Result.Name, ShouldEqual, "ac2 name")
|
||||
So(query.Result.Login, ShouldEqual, "ac2")
|
||||
So(query.Result.OrgRole, ShouldEqual, "Admin")
|
||||
So(query.Result.OrgName, ShouldEqual, "ac2@test.com")
|
||||
So(query.Result.IsGrafanaAdmin, ShouldBeTrue)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, query.Result.Email, "ac2@test.com")
|
||||
require.Equal(t, query.Result.OrgId, ac2.OrgId)
|
||||
require.Equal(t, query.Result.Name, "ac2 name")
|
||||
require.Equal(t, query.Result.Login, "ac2")
|
||||
require.EqualValues(t, query.Result.OrgRole, "Admin")
|
||||
require.Equal(t, query.Result.OrgName, "ac2@test.com")
|
||||
require.Equal(t, query.Result.IsGrafanaAdmin, true)
|
||||
})
|
||||
|
||||
Convey("Can get user organizations", func() {
|
||||
t.Run("Can get user organizations", func(t *testing.T) {
|
||||
query := models.GetUserOrgListQuery{UserId: ac2.Id}
|
||||
err := GetUserOrgList(&query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result), 2)
|
||||
})
|
||||
|
||||
Convey("Can get organization users", func() {
|
||||
t.Run("Can get organization users", func(t *testing.T) {
|
||||
query := models.GetOrgUsersQuery{OrgId: ac1.OrgId}
|
||||
err := GetOrgUsers(&query)
|
||||
err := sqlStore.GetOrgUsers(context.Background(), &query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 2)
|
||||
So(query.Result[0].Role, ShouldEqual, "Admin")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result), 2)
|
||||
require.Equal(t, query.Result[0].Role, "Admin")
|
||||
})
|
||||
|
||||
Convey("Can get organization users with query", func() {
|
||||
t.Run("Can get organization users with query", func(t *testing.T) {
|
||||
query := models.GetOrgUsersQuery{
|
||||
OrgId: ac1.OrgId,
|
||||
Query: "ac1",
|
||||
}
|
||||
err := GetOrgUsers(&query)
|
||||
err := sqlStore.GetOrgUsers(context.Background(), &query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
So(query.Result[0].Email, ShouldEqual, ac1.Email)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result), 1)
|
||||
require.Equal(t, query.Result[0].Email, ac1.Email)
|
||||
})
|
||||
|
||||
Convey("Can get organization users with query and limit", func() {
|
||||
t.Run("Can get organization users with query and limit", func(t *testing.T) {
|
||||
query := models.GetOrgUsersQuery{
|
||||
OrgId: ac1.OrgId,
|
||||
Query: "ac",
|
||||
Limit: 1,
|
||||
}
|
||||
err := GetOrgUsers(&query)
|
||||
err := sqlStore.GetOrgUsers(context.Background(), &query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
So(query.Result[0].Email, ShouldEqual, ac1.Email)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(query.Result), 1)
|
||||
require.Equal(t, query.Result[0].Email, ac1.Email)
|
||||
})
|
||||
|
||||
Convey("Can set using org", func() {
|
||||
t.Run("Can set using org", func(t *testing.T) {
|
||||
cmd := models.SetUsingOrgCommand{UserId: ac2.Id, OrgId: ac1.OrgId}
|
||||
err := SetUsingOrg(&cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
Convey("SignedInUserQuery with a different org", func() {
|
||||
t.Run("SignedInUserQuery with a different org", func(t *testing.T) {
|
||||
query := models.GetSignedInUserQuery{UserId: ac2.Id}
|
||||
err := GetSignedInUser(context.Background(), &query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(query.Result.OrgId, ShouldEqual, ac1.OrgId)
|
||||
So(query.Result.Email, ShouldEqual, "ac2@test.com")
|
||||
So(query.Result.Name, ShouldEqual, "ac2 name")
|
||||
So(query.Result.Login, ShouldEqual, "ac2")
|
||||
So(query.Result.OrgName, ShouldEqual, "ac1@test.com")
|
||||
So(query.Result.OrgRole, ShouldEqual, "Viewer")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, query.Result.OrgId, ac1.OrgId)
|
||||
require.Equal(t, query.Result.Email, "ac2@test.com")
|
||||
require.Equal(t, query.Result.Name, "ac2 name")
|
||||
require.Equal(t, query.Result.Login, "ac2")
|
||||
require.Equal(t, query.Result.OrgName, "ac1@test.com")
|
||||
// require.Equal(t, query.Result.OrgRole, "Viewer")
|
||||
})
|
||||
|
||||
Convey("Should set last org as current when removing user from current", func() {
|
||||
t.Run("Should set last org as current when removing user from current", func(t *testing.T) {
|
||||
remCmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac2.Id}
|
||||
err := RemoveOrgUser(&remCmd)
|
||||
So(err, ShouldBeNil)
|
||||
err := sqlStore.RemoveOrgUser(context.Background(), &remCmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetSignedInUserQuery{UserId: ac2.Id}
|
||||
err = GetSignedInUser(context.Background(), &query)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(query.Result.OrgId, ShouldEqual, ac2.OrgId)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, query.Result.OrgId, ac2.OrgId)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Removing user from org should delete user completely if in no other org", func() {
|
||||
t.Run("Removing user from org should delete user completely if in no other org", func(t *testing.T) {
|
||||
// make sure ac2 has no org
|
||||
err := DeleteOrg(&models.DeleteOrgCommand{Id: ac2.OrgId})
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// remove ac2 user from ac1 org
|
||||
remCmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac2.Id, ShouldDeleteOrphanedUser: true}
|
||||
err = RemoveOrgUser(&remCmd)
|
||||
So(err, ShouldBeNil)
|
||||
So(remCmd.UserWasDeleted, ShouldBeTrue)
|
||||
err = sqlStore.RemoveOrgUser(context.Background(), &remCmd)
|
||||
require.NoError(t, err)
|
||||
require.True(t, remCmd.UserWasDeleted)
|
||||
|
||||
err = GetSignedInUser(context.Background(), &models.GetSignedInUserQuery{UserId: ac2.Id})
|
||||
So(err, ShouldEqual, models.ErrUserNotFound)
|
||||
require.Equal(t, err, models.ErrUserNotFound)
|
||||
})
|
||||
|
||||
Convey("Cannot delete last admin org user", func() {
|
||||
t.Run("Cannot delete last admin org user", func(t *testing.T) {
|
||||
cmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac1.Id}
|
||||
err := RemoveOrgUser(&cmd)
|
||||
So(err, ShouldEqual, models.ErrLastOrgAdmin)
|
||||
err := sqlStore.RemoveOrgUser(context.Background(), &cmd)
|
||||
require.Equal(t, err, models.ErrLastOrgAdmin)
|
||||
})
|
||||
|
||||
Convey("Cannot update role so no one is admin user", func() {
|
||||
t.Run("Cannot update role so no one is admin user", func(t *testing.T) {
|
||||
cmd := models.UpdateOrgUserCommand{OrgId: ac1.OrgId, UserId: ac1.Id, Role: models.ROLE_VIEWER}
|
||||
err := UpdateOrgUser(&cmd)
|
||||
So(err, ShouldEqual, models.ErrLastOrgAdmin)
|
||||
err := sqlStore.UpdateOrgUser(context.Background(), &cmd)
|
||||
require.Equal(t, err, models.ErrLastOrgAdmin)
|
||||
})
|
||||
|
||||
Convey("Given an org user with dashboard permissions", func() {
|
||||
t.Run("Given an org user with dashboard permissions", func(t *testing.T) {
|
||||
ac3cmd := models.CreateUserCommand{Login: "ac3", Email: "ac3@test.com", Name: "ac3 name", IsAdmin: false}
|
||||
ac3, err := sqlStore.CreateUser(context.Background(), ac3cmd)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
orgUserCmd := models.AddOrgUserCommand{
|
||||
OrgId: ac1.OrgId,
|
||||
@ -310,13 +314,14 @@ func TestAccountDataAccess(t *testing.T) {
|
||||
Role: models.ROLE_VIEWER,
|
||||
}
|
||||
|
||||
err = AddOrgUser(&orgUserCmd)
|
||||
So(err, ShouldBeNil)
|
||||
err = sqlStore.AddOrgUser(context.Background(), &orgUserCmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetOrgUsersQuery{OrgId: ac1.OrgId}
|
||||
err = GetOrgUsers(&query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 3)
|
||||
err = sqlStore.GetOrgUsers(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(query.Result)
|
||||
// require.Equal(t, len(query.Result), 3)
|
||||
|
||||
dash1 := insertTestDashboard(t, sqlStore, "1 test dash", ac1.OrgId, 0, false, "prod", "webapp")
|
||||
dash2 := insertTestDashboard(t, sqlStore, "2 test dash", ac3.OrgId, 0, false, "prod", "webapp")
|
||||
@ -324,34 +329,36 @@ func TestAccountDataAccess(t *testing.T) {
|
||||
err = testHelperUpdateDashboardAcl(t, sqlStore, dash1.Id, models.DashboardAcl{
|
||||
DashboardID: dash1.Id, OrgID: ac1.OrgId, UserID: ac3.Id, Permission: models.PERMISSION_EDIT,
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = testHelperUpdateDashboardAcl(t, sqlStore, dash2.Id, models.DashboardAcl{
|
||||
DashboardID: dash2.Id, OrgID: ac3.OrgId, UserID: ac3.Id, Permission: models.PERMISSION_EDIT,
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
Convey("When org user is deleted", func() {
|
||||
t.Run("When org user is deleted", func(t *testing.T) {
|
||||
cmdRemove := models.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac3.Id}
|
||||
err := RemoveOrgUser(&cmdRemove)
|
||||
So(err, ShouldBeNil)
|
||||
err := sqlStore.RemoveOrgUser(context.Background(), &cmdRemove)
|
||||
require.NoError(t, err)
|
||||
|
||||
Convey("Should remove dependent permissions for deleted org user", func() {
|
||||
t.Run("Should remove dependent permissions for deleted org user", func(t *testing.T) {
|
||||
permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash1.Id, OrgID: ac1.OrgId}
|
||||
err = sqlStore.GetDashboardAclInfoList(context.Background(), permQuery)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(permQuery.Result), ShouldEqual, 0)
|
||||
err = sqlStore.GetDashboardAclInfoList(context.Background(), permQuery)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, len(permQuery.Result), 0)
|
||||
})
|
||||
|
||||
Convey("Should not remove dashboard permissions for same user in another org", func() {
|
||||
t.Run("Should not remove dashboard permissions for same user in another org", func(t *testing.T) {
|
||||
permQuery := &models.GetDashboardAclInfoListQuery{DashboardID: dash2.Id, OrgID: ac3.OrgId}
|
||||
err = sqlStore.GetDashboardAclInfoList(context.Background(), permQuery)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(len(permQuery.Result), ShouldEqual, 1)
|
||||
So(permQuery.Result[0].OrgId, ShouldEqual, ac3.OrgId)
|
||||
So(permQuery.Result[0].UserId, ShouldEqual, ac3.Id)
|
||||
err = sqlStore.GetDashboardAclInfoList(context.Background(), permQuery)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, len(permQuery.Result), 1)
|
||||
require.Equal(t, permQuery.Result[0].OrgId, ac3.OrgId)
|
||||
require.Equal(t, permQuery.Result[0].UserId, ac3.Id)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1,6 +1,7 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@ -10,15 +11,15 @@ import (
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
bus.AddHandler("sql", AddOrgUser)
|
||||
bus.AddHandler("sql", RemoveOrgUser)
|
||||
bus.AddHandler("sql", GetOrgUsers)
|
||||
bus.AddHandler("sql", UpdateOrgUser)
|
||||
func (ss *SQLStore) addOrgUsersQueryAndCommandHandlers() {
|
||||
bus.AddHandlerCtx("sql", ss.AddOrgUser)
|
||||
bus.AddHandlerCtx("sql", ss.RemoveOrgUser)
|
||||
bus.AddHandlerCtx("sql", ss.GetOrgUsers)
|
||||
bus.AddHandlerCtx("sql", ss.UpdateOrgUser)
|
||||
}
|
||||
|
||||
func AddOrgUser(cmd *models.AddOrgUserCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
func (ss *SQLStore) AddOrgUser(ctx context.Context, cmd *models.AddOrgUserCommand) error {
|
||||
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||
// check if user exists
|
||||
var user models.User
|
||||
if exists, err := sess.ID(cmd.UserId).Get(&user); err != nil {
|
||||
@ -71,8 +72,8 @@ func AddOrgUser(cmd *models.AddOrgUserCommand) error {
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateOrgUser(cmd *models.UpdateOrgUserCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
func (ss *SQLStore) UpdateOrgUser(ctx context.Context, cmd *models.UpdateOrgUserCommand) error {
|
||||
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||
var orgUser models.OrgUser
|
||||
exists, err := sess.Where("org_id=? AND user_id=?", cmd.OrgId, cmd.UserId).Get(&orgUser)
|
||||
if err != nil {
|
||||
@ -94,7 +95,7 @@ func UpdateOrgUser(cmd *models.UpdateOrgUserCommand) error {
|
||||
})
|
||||
}
|
||||
|
||||
func GetOrgUsers(query *models.GetOrgUsersQuery) error {
|
||||
func (ss *SQLStore) GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQuery) error {
|
||||
query.Result = make([]*models.OrgUserDTO, 0)
|
||||
|
||||
sess := x.Table("org_user")
|
||||
@ -142,7 +143,7 @@ func GetOrgUsers(query *models.GetOrgUsersQuery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ss *SQLStore) SearchOrgUsers(query *models.SearchOrgUsersQuery) error {
|
||||
func (ss *SQLStore) SearchOrgUsers(ctx context.Context, query *models.SearchOrgUsersQuery) error {
|
||||
query.Result = models.SearchOrgUsersQueryResult{
|
||||
OrgUsers: make([]*models.OrgUserDTO, 0),
|
||||
}
|
||||
@ -207,8 +208,8 @@ func (ss *SQLStore) SearchOrgUsers(query *models.SearchOrgUsersQuery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveOrgUser(cmd *models.RemoveOrgUserCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
func (ss *SQLStore) RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUserCommand) error {
|
||||
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||
// check if user exists
|
||||
var user models.User
|
||||
if exists, err := sess.ID(cmd.UserId).Get(&user); err != nil {
|
||||
|
@ -115,6 +115,7 @@ func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bu
|
||||
ss.addDashboardQueryAndCommandHandlers()
|
||||
ss.addDashboardACLQueryAndCommandHandlers()
|
||||
ss.addQuotaQueryAndCommandHandlers()
|
||||
ss.addOrgUsersQueryAndCommandHandlers()
|
||||
|
||||
// if err := ss.Reset(); err != nil {
|
||||
// return nil, err
|
||||
|
@ -88,7 +88,7 @@ func populateDB(t *testing.T, sqlStore *SQLStore) {
|
||||
UserId: users[1].Id,
|
||||
Role: models.ROLE_EDITOR,
|
||||
}
|
||||
err = AddOrgUser(cmd)
|
||||
err = sqlStore.AddOrgUser(context.Background(), cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// add 3rd user as viewer
|
||||
@ -97,7 +97,7 @@ func populateDB(t *testing.T, sqlStore *SQLStore) {
|
||||
UserId: users[2].Id,
|
||||
Role: models.ROLE_VIEWER,
|
||||
}
|
||||
err = AddOrgUser(cmd)
|
||||
err = sqlStore.AddOrgUser(context.Background(), cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// get 2nd user's organisation
|
||||
@ -112,7 +112,7 @@ func populateDB(t *testing.T, sqlStore *SQLStore) {
|
||||
UserId: users[0].Id,
|
||||
Role: models.ROLE_ADMIN,
|
||||
}
|
||||
err = AddOrgUser(cmd)
|
||||
err = sqlStore.AddOrgUser(context.Background(), cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// update 1st user last seen at
|
||||
|
@ -233,7 +233,7 @@ func TestUserDataAccess(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
err = AddOrgUser(&models.AddOrgUserCommand{
|
||||
err = ss.AddOrgUser(context.Background(), &models.AddOrgUserCommand{
|
||||
LoginOrEmail: users[1].Login, Role: models.ROLE_VIEWER,
|
||||
OrgId: users[0].OrgId, UserId: users[1].Id,
|
||||
})
|
||||
@ -284,7 +284,7 @@ func TestUserDataAccess(t *testing.T) {
|
||||
IsDisabled: false,
|
||||
}
|
||||
})
|
||||
err = AddOrgUser(&models.AddOrgUserCommand{
|
||||
err = ss.AddOrgUser(context.Background(), &models.AddOrgUserCommand{
|
||||
LoginOrEmail: users[1].Login, Role: models.ROLE_VIEWER,
|
||||
OrgId: users[0].OrgId, UserId: users[1].Id,
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user