Command: add conflict merge user command

- MergeUser will
	- replace all user_ids from conflicting users to the chosen userId
	- delete users whose user_ids are not the chosen user
- SameIdentification will
	- update chosen user with chosen email,login details
	- delete users whose user_ids are not the chosen user
This commit is contained in:
eleijonmarck committed 2022-07-20 14:02:15 +01:00
1 parent 3838a59fa1
commit 29adcd4e48
3 files changed
+145 -30

No files matched your search

@@ -111,32 +111,40 @@ func runConflictingUsersCommand() func(context *cli.Context) error {
cUser.Print()
// waiting for user to choose which user to merge to
logger.Infof("Choose which user to merge into:")
scanner := bufio.NewScanner(os.Stdin)
if ok := scanner.Scan(); !ok {
if err := scanner.Err(); err != nil {
return fmt.Errorf("can't read conflict option from stdin: %w", err)
}
return fmt.Errorf("can't read conflict option from stdin")
}
choosenUserToMergeInto := scanner.Text()
if !strings.Contains(cUser.Ids, choosenUserToMergeInto) {
return fmt.Errorf("not a conflicting user id")
}
v, err := strconv.ParseInt(choosenUserToMergeInto, 10, 64)
chosenUser, err := promptToMerge(cUser)
if err != nil {
return fmt.Errorf("could not parse id from string")
return err
}
otherUsers := cUser.Ids
logger.Infof("this will merge users %d into the choosen user %s\n\n", otherUsers, choosenUserToMergeInto)
logger.Infof("this will merge users %s into the chosen user %d\n\n", otherUsers, chosenUser)
if confirm() {
err = mergeUser(v, cUser, sqlStore)
err = mergeUser(context.Context, chosenUser, cUser, sqlStore)
if err != nil {
return fmt.Errorf("couldnt merge user with error %w", err)
return fmt.Errorf("could not merge user with error %w", err)
}
}
case SameIdentification:
return fmt.Errorf("have not implemented ways to deal with non mergeable users")
// waiting for user to choose which user to merge to
chosenUser, err := promptToMerge(cUser)
if err != nil {
return err
}
err = sqlStore.UpdateUser(context.Context, &models.UpdateUserCommand{UserId: chosenUser})
if err != nil {
return fmt.Errorf("could not update user with details %w", err)
}
otherUsers := strings.Split(cUser.Ids, ",")
for _, oUser := range otherUsers {
oUser, err := strconv.ParseInt(oUser, 10, 64)
if err != nil {
return err
}
err = sqlStore.DeleteUser(context.Context, &models.DeleteUserCommand{UserId: oUser})
if err != nil {
return fmt.Errorf("could not update user with details %w", err)
}
}
default:
logger.Infof("could not identify the conflict resolution for found users %s", cUser.Ids)
continue
@@ -237,7 +245,7 @@ func (cUser ConflictingUsers) Conflict() conflictType {
return cType
}
func mergeUser(mergeIntoUser int64, cUser ConflictingUsers, sqlStore *sqlstore.SQLStore) error {
func mergeUser(ctx context.Context, mergeIntoUser int64, cUser ConflictingUsers, sqlStore *sqlstore.SQLStore) error {
stringIds := strings.Split(cUser.Ids, ",")
fromUserIds := make([]int64, 0, len(stringIds))
for _, raw := range stringIds {
@@ -247,7 +255,7 @@ func mergeUser(mergeIntoUser int64, cUser ConflictingUsers, sqlStore *sqlstore.S
}
fromUserIds = append(fromUserIds, v)
}
return sqlStore.MergeUser(mergeIntoUser, fromUserIds)
return sqlStore.MergeUser(ctx, mergeIntoUser, fromUserIds)
}
type ConflictingUsers struct {
@@ -46,11 +46,74 @@ func TestUserManagerListConflictingUsers(t *testing.T) {
}
_, err = sqlStore.CreateUser(context.Background(), dupUserLogincmd)
require.NoError(t, err)
// require metrics and statistics to be 2
m, err := GetUsersWithConflictingEmailsOrLogins(context.Background(), sqlStore)
t.Logf("%v+", m)
require.NoError(t, err)
require.Equal(t, 1, len(m))
}
})
}
func TestMergeUser(t *testing.T) {
t.Run("should be able to merge user", func(t *testing.T) {
// Restore after destructive operation
sqlStore := sqlstore.InitTestDB(t)
const testOrgID int64 = 1
// "Skipping conflicting users test for mysql as it does make unique constraint case insensitive by default
if sqlStore.GetDialect().DriverName() != "mysql" {
// setup
dupUserEmailcmd := user.CreateUserCommand{
Email: "USERDUPLICATETEST1@TEST.COM",
Name: "user name 1",
Login: "USER_DUPLICATE_TEST_1_LOGIN",
OrgID: testOrgID,
}
userWithUpperCase, err := sqlStore.CreateUser(context.Background(), dupUserEmailcmd)
require.NoError(t, err)
// add additional user with conflicting login where DOMAIN is upper case
dupUserLogincmd := user.CreateUserCommand{
Email: "userduplicatetest1@test.com",
Name: "user name 1",
Login: "user_duplicate_test_1_login",
OrgID: testOrgID,
}
userWithLowerCase, err := sqlStore.CreateUser(context.Background(), dupUserLogincmd)
require.NoError(t, err)
// fromUser should be replaced by userWithLowerCase
team1, err := sqlStore.CreateTeam("group1 name", "test1@test.com", testOrgID)
require.NoError(t, err)
err = sqlStore.AddTeamMember(userWithUpperCase.ID, testOrgID, team1.Id, false, 0)
require.NoError(t, err)
// setup finished
m, err := GetUsersWithConflictingEmailsOrLogins(context.Background(), sqlStore)
require.NoError(t, err)
mergeErr := mergeUser(context.Background(), userWithLowerCase.ID, m[0], sqlStore)
require.NoError(t, mergeErr)
// start test
// fromUser should be deleted after merger
t.Logf("testing getting user")
query := &models.GetUserByIdQuery{Id: userWithUpperCase.ID}
err = sqlStore.GetUserById(context.Background(), query)
require.Error(t, models.ErrUserNotFound, err)
testUser := &models.SignedInUser{
OrgId: testOrgID,
Permissions: map[int64]map[string][]string{
1: {
ac.ActionTeamsRead: []string{ac.ScopeTeamsAll},
ac.ActionOrgUsersRead: []string{ac.ScopeUsersAll},
},
},
}
t.Logf("testing getting team member")
q1 := &models.GetTeamMembersQuery{OrgId: testOrgID, TeamId: team1.Id, SignedInUser: testUser}
err = sqlStore.GetTeamMembers(context.Background(), q1)
require.NoError(t, err)
require.Equal(t, 0, len(q1.Result))
}
})
}