chore: remove CreateUser from sqlstore & replace with userService.CreateUserForTests (#59910)

This commit is contained in:
Kristin Laemmert
2022-12-07 11:03:22 -05:00
committed by GitHub
parent d036225f7b
commit 70fbf47022
44 changed files with 943 additions and 758 deletions
+41 -6
View File
@@ -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
+61 -38
View File
@@ -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
}
+16
View File
@@ -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
}
+203 -14
View File
@@ -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
}
+5 -1
View File
@@ -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
}