chore: remove CreateUser from sqlstore & replace with userService.CreateUserForTests (#59910)
This commit is contained in:
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -24,6 +23,7 @@ type store interface {
|
||||
GetByID(context.Context, int64) (*user.User, error)
|
||||
GetNotServiceAccount(context.Context, int64) (*user.User, error)
|
||||
Delete(context.Context, int64) error
|
||||
LoginConflict(ctx context.Context, login, email string, caseInsensitive bool) error
|
||||
CaseInsensitiveLoginConflict(context.Context, string, string) error
|
||||
GetByLogin(context.Context, *user.GetUserByLoginQuery) (*user.User, error)
|
||||
GetByEmail(context.Context, *user.GetUserByEmailQuery) (*user.User, error)
|
||||
@@ -59,12 +59,11 @@ func ProvideStore(db db.DB, cfg *setting.Cfg) sqlStore {
|
||||
}
|
||||
|
||||
func (ss *sqlStore) Insert(ctx context.Context, cmd *user.User) (int64, error) {
|
||||
var userID int64
|
||||
var err error
|
||||
err = ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
sess.UseBool("is_admin")
|
||||
|
||||
if userID, err = sess.Insert(cmd); err != nil {
|
||||
if _, err = sess.Insert(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
sess.PublishAfterCommit(&events.UserCreated{
|
||||
@@ -79,7 +78,7 @@ func (ss *sqlStore) Insert(ctx context.Context, cmd *user.User) (int64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return userID, nil
|
||||
return cmd.ID, nil
|
||||
}
|
||||
|
||||
func (ss *sqlStore) Get(ctx context.Context, usr *user.User) (*user.User, error) {
|
||||
@@ -185,7 +184,6 @@ func (ss *sqlStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQu
|
||||
where = "LOWER(email)=LOWER(?)"
|
||||
}
|
||||
has, err = sess.Where(ss.notServiceAccountFilter()).Where(where, query.LoginOrEmail).Get(usr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -264,6 +262,43 @@ func (ss *sqlStore) userCaseInsensitiveLoginConflict(ctx context.Context, sess *
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoginConflict returns an error if the provided email or login are already
|
||||
// associated with a user. If caseInsensitive is true the search is not case
|
||||
// sensitive.
|
||||
func (ss *sqlStore) LoginConflict(ctx context.Context, login, email string, caseInsensitive bool) error {
|
||||
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
return ss.loginConflict(ctx, sess, login, email, caseInsensitive)
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (ss *sqlStore) loginConflict(ctx context.Context, sess *db.Session, login, email string, caseInsensitive bool) error {
|
||||
users := make([]user.User, 0)
|
||||
where := "email=? OR login=?"
|
||||
if caseInsensitive {
|
||||
where = "LOWER(email)=LOWER(?) OR LOWER(login)=LOWER(?)"
|
||||
login = strings.ToLower(login)
|
||||
email = strings.ToLower(email)
|
||||
}
|
||||
|
||||
exists, err := sess.Where(where, email, login).Get(&user.User{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return user.ErrUserAlreadyExists
|
||||
}
|
||||
if err := sess.Where("LOWER(email)=LOWER(?) OR LOWER(login)=LOWER(?)",
|
||||
email, login).Find(&users); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(users) > 1 {
|
||||
return &user.ErrCaseInsensitiveLoginConflict{Users: users}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ss *sqlStore) Update(ctx context.Context, cmd *user.UpdateUserCommand) error {
|
||||
if ss.cfg.CaseInsensitiveLogin {
|
||||
cmd.Login = strings.ToLower(cmd.Login)
|
||||
@@ -470,7 +505,7 @@ func (ss *sqlStore) Count(ctx context.Context) (int64, error) {
|
||||
}
|
||||
|
||||
r := result{}
|
||||
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s WHERE is_service_account=%s", ss.db.GetDialect().Quote("user"), ss.db.GetDialect().BooleanStr(false))
|
||||
if _, err := sess.SQL(rawSQL).Get(&r); err != nil {
|
||||
return err
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -31,6 +30,8 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
orgService, err := orgimpl.ProvideService(ss, ss.Cfg, quotaService)
|
||||
require.NoError(t, err)
|
||||
userStore := ProvideStore(ss, setting.NewCfg())
|
||||
usrSvc, err := ProvideService(ss, orgService, ss.Cfg, nil, nil, quotaService)
|
||||
require.NoError(t, err)
|
||||
usr := &user.SignedInUser{
|
||||
OrgID: 1,
|
||||
Permissions: map[int64]map[string][]string{1: {"users:read": {"global.users:*"}}},
|
||||
@@ -73,12 +74,14 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
|
||||
t.Run("Testing DB - creates and loads user", func(t *testing.T) {
|
||||
ss := db.InitTestDB(t)
|
||||
_, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg)
|
||||
|
||||
cmd := user.CreateUserCommand{
|
||||
Email: "usertest@test.com",
|
||||
Name: "user name",
|
||||
Login: "user_test_login",
|
||||
}
|
||||
usr, err := ss.CreateUser(context.Background(), cmd)
|
||||
usr, err := usrSvc.Create(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := userStore.GetByID(context.Background(), usr.ID)
|
||||
@@ -147,7 +150,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
Login: "user_email_conflict",
|
||||
}
|
||||
// userEmailConflict
|
||||
_, err := ss.CreateUser(context.Background(), cmd)
|
||||
_, err = usrSvc.Create(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd = user.CreateUserCommand{
|
||||
@@ -155,7 +158,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
Name: "user name",
|
||||
Login: "user_email_conflict_two",
|
||||
}
|
||||
_, err = ss.CreateUser(context.Background(), cmd)
|
||||
_, err := usrSvc.Create(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd = user.CreateUserCommand{
|
||||
@@ -164,7 +167,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
Login: "user_test_login_conflict",
|
||||
}
|
||||
// userLoginConflict
|
||||
_, err = ss.CreateUser(context.Background(), cmd)
|
||||
_, err = usrSvc.Create(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd = user.CreateUserCommand{
|
||||
@@ -172,7 +175,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
Name: "user name",
|
||||
Login: "user_test_login_CONFLICT",
|
||||
}
|
||||
_, err = ss.CreateUser(context.Background(), cmd)
|
||||
_, err = usrSvc.Create(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
ss.Cfg.CaseInsensitiveLogin = true
|
||||
@@ -262,7 +265,9 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get signed in user", func(t *testing.T) {
|
||||
users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
ss := db.InitTestDB(t)
|
||||
orgService, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg)
|
||||
users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -300,26 +305,24 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Testing DB - grafana admin users", func(t *testing.T) {
|
||||
ss = db.InitTestDB(t)
|
||||
|
||||
ss := db.InitTestDB(t)
|
||||
_, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg)
|
||||
createUserCmd := user.CreateUserCommand{
|
||||
Email: fmt.Sprint("admin", "@test.com"),
|
||||
Name: "admin",
|
||||
Login: "admin",
|
||||
IsAdmin: true,
|
||||
}
|
||||
usr, err := ss.CreateUser(context.Background(), createUserCmd)
|
||||
usr, err := usrSvc.Create(context.Background(), &createUserCmd)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Cannot make themselves a non-admin
|
||||
updatePermsError := userStore.UpdatePermissions(context.Background(), usr.ID, false)
|
||||
|
||||
require.Equal(t, user.ErrLastGrafanaAdmin, updatePermsError)
|
||||
|
||||
query := user.GetUserByIDQuery{ID: usr.ID}
|
||||
queryResult, getUserError := userStore.GetByID(context.Background(), query.ID)
|
||||
require.Nil(t, getUserError)
|
||||
|
||||
require.True(t, queryResult.IsAdmin)
|
||||
|
||||
// One user
|
||||
@@ -330,7 +333,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
Name: "user",
|
||||
Login: username,
|
||||
}
|
||||
_, err = ss.CreateUser(context.Background(), createUserCmd)
|
||||
_, err = usrSvc.Create(context.Background(), &createUserCmd)
|
||||
require.Nil(t, err)
|
||||
|
||||
// When trying to create a new user with the same email, an error is returned
|
||||
@@ -340,8 +343,8 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
Login: "user2",
|
||||
SkipOrgSetup: true,
|
||||
}
|
||||
_, err = ss.CreateUser(context.Background(), createUserCmd)
|
||||
require.Equal(t, err, user.ErrUserAlreadyExists)
|
||||
_, err = usrSvc.Create(context.Background(), &createUserCmd)
|
||||
require.Equal(t, user.ErrUserAlreadyExists, err)
|
||||
|
||||
// When trying to create a new user with the same login, an error is returned
|
||||
createUserCmd = user.CreateUserCommand{
|
||||
@@ -350,8 +353,8 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
Login: username,
|
||||
SkipOrgSetup: true,
|
||||
}
|
||||
_, err = ss.CreateUser(context.Background(), createUserCmd)
|
||||
require.Equal(t, err, user.ErrUserAlreadyExists)
|
||||
_, err = usrSvc.Create(context.Background(), &createUserCmd)
|
||||
require.Equal(t, user.ErrUserAlreadyExists, err)
|
||||
})
|
||||
|
||||
t.Run("GetProfile", func(t *testing.T) {
|
||||
@@ -366,7 +369,10 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
|
||||
t.Run("Testing DB - return list users based on their is_disabled flag", func(t *testing.T) {
|
||||
ss = db.InitTestDB(t)
|
||||
createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
_, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg)
|
||||
userStore := ProvideStore(ss, ss.Cfg)
|
||||
|
||||
createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -379,7 +385,6 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
query := user.SearchUsersQuery{IsDisabled: &isDisabled, SignedInUser: usr}
|
||||
result, err := userStore.Search(context.Background(), &query)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Len(t, result.Users, 2)
|
||||
|
||||
first, third := false, false
|
||||
@@ -397,8 +402,10 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
require.True(t, third)
|
||||
|
||||
// Re-init DB
|
||||
ss = db.InitTestDB(t)
|
||||
users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
ss := db.InitTestDB(t)
|
||||
orgService, usrSvc = createOrgAndUserSvc(t, ss, ss.Cfg)
|
||||
|
||||
users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -432,7 +439,8 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
// A user is an org member and has been assigned permissions
|
||||
// Re-init DB
|
||||
ss = db.InitTestDB(t)
|
||||
users = createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
orgService, usrSvc = createOrgAndUserSvc(t, ss, ss.Cfg)
|
||||
users = createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -487,7 +495,12 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
|
||||
t.Run("Testing DB - return list of users that the SignedInUser has permission to read", func(t *testing.T) {
|
||||
ss := db.InitTestDB(t)
|
||||
createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
orgService, err := orgimpl.ProvideService(ss, ss.Cfg, quotaService)
|
||||
require.NoError(t, err)
|
||||
usrSvc, err := ProvideService(ss, orgService, ss.Cfg, nil, nil, quotaService)
|
||||
require.NoError(t, err)
|
||||
|
||||
createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -508,7 +521,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
ss = db.InitTestDB(t)
|
||||
|
||||
t.Run("Testing DB - enable all users", func(t *testing.T) {
|
||||
users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -541,12 +554,12 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
ac2cmd := user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true}
|
||||
serviceaccountcmd := user.CreateUserCommand{Login: "serviceaccount", Email: "service@test.com", Name: "serviceaccount name", IsAdmin: true, IsServiceAccount: true}
|
||||
|
||||
_, err := ss.CreateUser(context.Background(), ac1cmd)
|
||||
_, err := usrSvc.Create(context.Background(), &ac1cmd)
|
||||
require.NoError(t, err)
|
||||
_, err = ss.CreateUser(context.Background(), ac2cmd)
|
||||
_, err = usrSvc.Create(context.Background(), &ac2cmd)
|
||||
require.NoError(t, err)
|
||||
// user only used for making sure we filter out the service accounts
|
||||
_, err = ss.CreateUser(context.Background(), serviceaccountcmd)
|
||||
_, err = usrSvc.Create(context.Background(), &serviceaccountcmd)
|
||||
require.NoError(t, err)
|
||||
query := user.SearchUsersQuery{Query: "", SignedInUser: &user.SignedInUser{
|
||||
OrgID: 1,
|
||||
@@ -564,7 +577,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
ss = db.InitTestDB(t)
|
||||
|
||||
t.Run("Testing DB - disable only specific users", func(t *testing.T) {
|
||||
users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -594,7 +607,6 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
|
||||
// Check if user id is in the userIdsToDisable list
|
||||
for _, disabledUserId := range userIdsToDisable {
|
||||
fmt.Println(user.ID, disabledUserId)
|
||||
if user.ID == disabledUserId {
|
||||
require.True(t, user.IsDisabled)
|
||||
shouldBeDisabled = true
|
||||
@@ -612,7 +624,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
|
||||
t.Run("Testing DB - search users", func(t *testing.T) {
|
||||
// Since previous tests were destructive
|
||||
createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -636,7 +648,7 @@ func TestIntegrationUserDataAccess(t *testing.T) {
|
||||
t.Run("Testing DB - multiple users", func(t *testing.T) {
|
||||
ss = db.InitTestDB(t)
|
||||
|
||||
createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("user", i, "@test.com"),
|
||||
Name: fmt.Sprint("user", i),
|
||||
@@ -729,8 +741,9 @@ func TestIntegrationUserUpdate(t *testing.T) {
|
||||
|
||||
ss := db.InitTestDB(t)
|
||||
userStore := ProvideStore(ss, setting.NewCfg())
|
||||
_, usrSvc := createOrgAndUserSvc(t, ss, ss.Cfg)
|
||||
|
||||
users := createFiveTestUsers(t, ss, func(i int) *user.CreateUserCommand {
|
||||
users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
|
||||
return &user.CreateUserCommand{
|
||||
Email: fmt.Sprint("USER", i, "@test.com"),
|
||||
Name: fmt.Sprint("USER", i),
|
||||
@@ -789,17 +802,15 @@ func TestIntegrationUserUpdate(t *testing.T) {
|
||||
ss.Cfg.CaseInsensitiveLogin = false
|
||||
}
|
||||
|
||||
func createFiveTestUsers(t *testing.T, sqlStore *sqlstore.SQLStore, fn func(i int) *user.CreateUserCommand) []user.User {
|
||||
func createFiveTestUsers(t *testing.T, svc user.Service, fn func(i int) *user.CreateUserCommand) []user.User {
|
||||
t.Helper()
|
||||
|
||||
users := []user.User{}
|
||||
users := make([]user.User, 5)
|
||||
for i := 0; i < 5; i++ {
|
||||
cmd := fn(i)
|
||||
|
||||
user, err := sqlStore.CreateUser(context.Background(), *cmd)
|
||||
users = append(users, *user)
|
||||
|
||||
user, err := svc.CreateUserForTests(context.Background(), cmd)
|
||||
require.Nil(t, err)
|
||||
users[i] = *user
|
||||
}
|
||||
|
||||
return users
|
||||
@@ -924,3 +935,15 @@ func (ss *sqlStore) getDashboardACLInfoList(query *models.GetDashboardACLInfoLis
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createOrgAndUserSvc(t *testing.T, store db.DB, cfg *setting.Cfg) (org.Service, user.Service) {
|
||||
t.Helper()
|
||||
|
||||
quotaService := quotaimpl.ProvideService(store, cfg)
|
||||
orgService, err := orgimpl.ProvideService(store, cfg, quotaService)
|
||||
require.NoError(t, err)
|
||||
usrSvc, err := ProvideService(store, orgService, cfg, nil, nil, quotaService)
|
||||
require.NoError(t, err)
|
||||
|
||||
return orgService, usrSvc
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package userimpl
|
||||
|
||||
import "time"
|
||||
|
||||
// timeNow wraps time.Now so it can be mocked in tests.
|
||||
var timeNow = time.Now
|
||||
|
||||
func MockTimeNow(constTime time.Time) {
|
||||
timeNow = func() time.Time {
|
||||
return constTime
|
||||
}
|
||||
}
|
||||
|
||||
func ResetTimeNow() {
|
||||
timeNow = time.Now
|
||||
}
|
||||
@@ -82,32 +82,27 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
SkipOrgSetup: cmd.SkipOrgSetup,
|
||||
}
|
||||
orgID, err := s.orgService.GetIDForNewUser(ctx, cmdOrg)
|
||||
cmd.OrgID = orgID
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cmd.Email == "" {
|
||||
cmd.Email = cmd.Login
|
||||
}
|
||||
usr := &user.User{
|
||||
Login: cmd.Login,
|
||||
Email: cmd.Email,
|
||||
}
|
||||
usr, err = s.store.Get(ctx, usr)
|
||||
if err != nil && !errors.Is(err, user.ErrUserNotFound) {
|
||||
return usr, err
|
||||
|
||||
err = s.store.LoginConflict(ctx, cmd.Login, cmd.Email, s.cfg.CaseInsensitiveLogin)
|
||||
if err != nil {
|
||||
return nil, user.ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
// create user
|
||||
usr = &user.User{
|
||||
usr := &user.User{
|
||||
Email: cmd.Email,
|
||||
Name: cmd.Name,
|
||||
Login: cmd.Login,
|
||||
Company: cmd.Company,
|
||||
IsAdmin: cmd.IsAdmin,
|
||||
IsDisabled: cmd.IsDisabled,
|
||||
OrgID: cmd.OrgID,
|
||||
OrgID: orgID,
|
||||
EmailVerified: cmd.EmailVerified,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
@@ -134,7 +129,7 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
usr.Password = encodedPassword
|
||||
}
|
||||
|
||||
userID, err := s.store.Insert(ctx, usr)
|
||||
_, err = s.store.Insert(ctx, usr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -158,11 +153,10 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
}
|
||||
_, err = s.orgService.InsertOrgUser(ctx, &orgUser)
|
||||
if err != nil {
|
||||
err := s.store.Delete(ctx, userID)
|
||||
err := s.store.Delete(ctx, usr.ID)
|
||||
return usr, err
|
||||
}
|
||||
}
|
||||
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
@@ -354,3 +348,198 @@ func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
||||
limits.Set(globalQuotaTag, cfg.Quota.Global.User)
|
||||
return limits, nil
|
||||
}
|
||||
|
||||
// CreateUserForTests creates a test user and optionally an organization. Unlike
|
||||
// Create, `cmd.SkipOrgSetup` toggles whether or not to create an org for the
|
||||
// test user if there isn't already an existing org. This must only be used in tests.
|
||||
func (s *Service) CreateUserForTests(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) {
|
||||
var orgID int64 = -1
|
||||
var err error
|
||||
if !cmd.SkipOrgSetup {
|
||||
orgID, err = s.getOrgIDForNewUser(ctx, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.Email == "" {
|
||||
cmd.Email = cmd.Login
|
||||
}
|
||||
|
||||
usr, err := s.GetByLogin(ctx, &user.GetUserByLoginQuery{LoginOrEmail: cmd.Login})
|
||||
if err != nil && !errors.Is(err, user.ErrUserNotFound) {
|
||||
return usr, err
|
||||
} else if err == nil { // user exists
|
||||
return usr, err
|
||||
}
|
||||
|
||||
// create user
|
||||
usr = &user.User{
|
||||
Email: cmd.Email,
|
||||
Name: cmd.Name,
|
||||
Login: cmd.Login,
|
||||
Company: cmd.Company,
|
||||
IsAdmin: cmd.IsAdmin,
|
||||
IsDisabled: cmd.IsDisabled,
|
||||
OrgID: orgID,
|
||||
EmailVerified: cmd.EmailVerified,
|
||||
Created: timeNow(),
|
||||
Updated: timeNow(),
|
||||
LastSeenAt: timeNow().AddDate(-10, 0, 0),
|
||||
IsServiceAccount: cmd.IsServiceAccount,
|
||||
}
|
||||
|
||||
salt, err := util.GetRandomString(10)
|
||||
if err != nil {
|
||||
return usr, err
|
||||
}
|
||||
usr.Salt = salt
|
||||
rands, err := util.GetRandomString(10)
|
||||
if err != nil {
|
||||
return usr, err
|
||||
}
|
||||
usr.Rands = rands
|
||||
|
||||
if len(cmd.Password) > 0 {
|
||||
encodedPassword, err := util.EncodePassword(cmd.Password, usr.Salt)
|
||||
if err != nil {
|
||||
return usr, err
|
||||
}
|
||||
usr.Password = encodedPassword
|
||||
}
|
||||
|
||||
_, err = s.store.Insert(ctx, usr)
|
||||
if err != nil {
|
||||
return usr, err
|
||||
}
|
||||
|
||||
// create org user link
|
||||
if !cmd.SkipOrgSetup {
|
||||
orgCmd := &org.AddOrgUserCommand{
|
||||
OrgID: orgID,
|
||||
UserID: usr.ID,
|
||||
Role: org.RoleAdmin,
|
||||
AllowAddingServiceAccount: true,
|
||||
}
|
||||
|
||||
if s.cfg.AutoAssignOrg && !usr.IsAdmin {
|
||||
if len(cmd.DefaultOrgRole) > 0 {
|
||||
orgCmd.Role = org.RoleType(cmd.DefaultOrgRole)
|
||||
} else {
|
||||
orgCmd.Role = org.RoleType(s.cfg.AutoAssignOrgRole)
|
||||
}
|
||||
}
|
||||
|
||||
if err = s.orgService.AddOrgUser(ctx, orgCmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
func (s *Service) getOrgIDForNewUser(ctx context.Context, cmd *user.CreateUserCommand) (int64, error) {
|
||||
if s.cfg.AutoAssignOrg && cmd.OrgID != 0 {
|
||||
if _, err := s.orgService.GetByID(ctx, &org.GetOrgByIdQuery{ID: cmd.OrgID}); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return cmd.OrgID, nil
|
||||
}
|
||||
|
||||
orgName := cmd.OrgName
|
||||
if orgName == "" {
|
||||
orgName = util.StringsFallback2(cmd.Email, cmd.Login)
|
||||
}
|
||||
|
||||
orgID, err := s.orgService.GetOrCreate(ctx, orgName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return orgID, err
|
||||
}
|
||||
|
||||
// CreateServiceAccount is a copy of Create with a single difference; it will create the OrgUser service account.
|
||||
func (s *Service) CreateServiceAccount(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) {
|
||||
cmdOrg := org.GetOrgIDForNewUserCommand{
|
||||
Email: cmd.Email,
|
||||
Login: cmd.Login,
|
||||
OrgID: cmd.OrgID,
|
||||
OrgName: cmd.OrgName,
|
||||
SkipOrgSetup: cmd.SkipOrgSetup,
|
||||
}
|
||||
orgID, err := s.orgService.GetIDForNewUser(ctx, cmdOrg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cmd.Email == "" {
|
||||
cmd.Email = cmd.Login
|
||||
}
|
||||
|
||||
err = s.store.LoginConflict(ctx, cmd.Login, cmd.Email, s.cfg.CaseInsensitiveLogin)
|
||||
if err != nil {
|
||||
return nil, user.ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
// create user
|
||||
usr := &user.User{
|
||||
Email: cmd.Email,
|
||||
Name: cmd.Name,
|
||||
Login: cmd.Login,
|
||||
Company: cmd.Company,
|
||||
IsAdmin: cmd.IsAdmin,
|
||||
IsDisabled: cmd.IsDisabled,
|
||||
OrgID: cmd.OrgID,
|
||||
EmailVerified: cmd.EmailVerified,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
LastSeenAt: time.Now().AddDate(-10, 0, 0),
|
||||
IsServiceAccount: cmd.IsServiceAccount,
|
||||
}
|
||||
|
||||
salt, err := util.GetRandomString(10)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usr.Salt = salt
|
||||
rands, err := util.GetRandomString(10)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usr.Rands = rands
|
||||
|
||||
if len(cmd.Password) > 0 {
|
||||
encodedPassword, err := util.EncodePassword(cmd.Password, usr.Salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usr.Password = encodedPassword
|
||||
}
|
||||
|
||||
_, err = s.store.Insert(ctx, usr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create org user link
|
||||
if !cmd.SkipOrgSetup {
|
||||
orgCmd := &org.AddOrgUserCommand{
|
||||
OrgID: orgID,
|
||||
UserID: usr.ID,
|
||||
Role: org.RoleAdmin,
|
||||
AllowAddingServiceAccount: true,
|
||||
}
|
||||
|
||||
if s.cfg.AutoAssignOrg && !usr.IsAdmin {
|
||||
if len(cmd.DefaultOrgRole) > 0 {
|
||||
orgCmd.Role = org.RoleType(cmd.DefaultOrgRole)
|
||||
} else {
|
||||
orgCmd.Role = org.RoleType(s.cfg.AutoAssignOrgRole)
|
||||
}
|
||||
}
|
||||
|
||||
if err = s.orgService.AddOrgUser(ctx, orgCmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ func TestUserService(t *testing.T) {
|
||||
cacheService: localcache.ProvideService(),
|
||||
teamService: &teamtest.FakeService{},
|
||||
}
|
||||
userService.cfg = setting.NewCfg()
|
||||
|
||||
t.Run("create user", func(t *testing.T) {
|
||||
_, err := userService.Create(context.Background(), &user.CreateUserCommand{
|
||||
@@ -44,7 +45,6 @@ func TestUserService(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "login", u.Login)
|
||||
require.Equal(t, "name", u.Name)
|
||||
|
||||
require.Equal(t, "email", u.Email)
|
||||
})
|
||||
|
||||
@@ -229,6 +229,10 @@ func (f *FakeUserStore) CaseInsensitiveLoginConflict(context.Context, string, st
|
||||
return f.ExpectedError
|
||||
}
|
||||
|
||||
func (f *FakeUserStore) LoginConflict(context.Context, string, string, bool) error {
|
||||
return f.ExpectedError
|
||||
}
|
||||
|
||||
func (f *FakeUserStore) GetByLogin(ctx context.Context, query *user.GetUserByLoginQuery) (*user.User, error) {
|
||||
return f.ExpectedUser, f.ExpectedError
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user