[MM-34725] app/user: check if username or email is in use before patching a user (#17392)

* app/user: check if username or email is in use before patching a user

* reflect review comments

* fix tests
This commit is contained in:
Ibrahim Serdar Acikgoz
2021-04-16 18:41:32 +03:00
committed by GitHub
parent 3ea75332e7
commit 3a13987ee1
23 changed files with 57 additions and 85 deletions

View File

@@ -178,11 +178,17 @@ func (a *App) PatchBot(botUserId string, botPatch *model.BotPatch) (*model.Bot,
if nErr != nil {
var appErr *model.AppError
var invErr *store.ErrInvalidInput
var conErr *store.ErrConflict
switch {
case errors.As(nErr, &appErr):
return nil, appErr
case errors.As(nErr, &invErr):
return nil, model.NewAppError("PatchBot", "app.user.update.find.app_error", nil, invErr.Error(), http.StatusBadRequest)
return nil, model.NewAppError("PatchBot", "app.user.update.find.app_error", nil, nErr.Error(), http.StatusBadRequest)
case errors.As(nErr, &conErr):
if cErr, ok := nErr.(*store.ErrConflict); ok && cErr.Resource == "Username" {
return nil, model.NewAppError("PatchBot", "app.user.save.username_exists.app_error", nil, nErr.Error(), http.StatusBadRequest)
}
return nil, model.NewAppError("PatchBot", "app.user.save.email_exists.app_error", nil, nErr.Error(), http.StatusBadRequest)
default:
return nil, model.NewAppError("PatchBot", "app.user.update.finding.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}

View File

@@ -204,7 +204,7 @@ func TestPatchBot(t *testing.T) {
_, err = th.App.PatchBot(bot.UserId, botPatch)
require.NotNil(t, err)
require.Equal(t, "app.user.update.find.app_error", err.Id)
require.Equal(t, "app.user.save.username_exists.app_error", err.Id)
})
}

View File

@@ -1281,15 +1281,13 @@ func (a *App) UpdateUser(user *model.User, sendNotifications bool) (*model.User,
}
}
if _, appErr := a.GetUserByEmail(user.Email); appErr == nil {
return nil, model.NewAppError("UpdateUser", "store.sql_user.update.email_taken.app_error", nil, "user_id="+user.Id, http.StatusBadRequest)
}
// Don't set new eMail on user account if email verification is required, this will be done as a post-verification action
// to avoid users being able to set non-controlled eMails as their account email
if *a.Config().EmailSettings.RequireEmailVerification {
newEmail = user.Email
// Don't set new eMail on user account if email verification is required, this will be done as a post-verification action
// to avoid users being able to set non-controlled eMails as their account email
if _, appErr := a.GetUserByEmail(newEmail); appErr == nil {
return nil, model.NewAppError("UpdateUser", "app.user.save.email_exists.app_error", nil, "user_id="+user.Id, http.StatusBadRequest)
}
// When a bot is created, prev.Email will be an autogenerated faked email,
// which will not match a CLI email input during bot to user conversions.
@@ -1305,11 +1303,17 @@ func (a *App) UpdateUser(user *model.User, sendNotifications bool) (*model.User,
if err != nil {
var appErr *model.AppError
var invErr *store.ErrInvalidInput
var conErr *store.ErrConflict
switch {
case errors.As(err, &appErr):
return nil, appErr
case errors.As(err, &invErr):
return nil, model.NewAppError("UpdateUser", "app.user.update.find.app_error", nil, invErr.Error(), http.StatusBadRequest)
case errors.As(err, &conErr):
if cErr, ok := err.(*store.ErrConflict); ok && cErr.Resource == "Username" {
return nil, model.NewAppError("UpdateUser", "app.user.save.username_exists.app_error", nil, "", http.StatusBadRequest)
}
return nil, model.NewAppError("UpdateUser", "app.user.save.email_exists.app_error", nil, "", http.StatusBadRequest)
default:
return nil, model.NewAppError("UpdateUser", "app.user.update.finding.app_error", nil, err.Error(), http.StatusInternalServerError)
}

View File

@@ -471,7 +471,7 @@ func TestUpdateUserEmail(t *testing.T) {
user.Email = newEmail
user3, err := th.App.UpdateUser(user, false)
require.NotNil(t, err)
assert.Equal(t, err.Id, "store.sql_user.update.email_taken.app_error")
assert.Equal(t, err.Id, "app.user.save.email_exists.app_error")
assert.Nil(t, user3)
})
@@ -514,7 +514,7 @@ func TestUpdateUserEmail(t *testing.T) {
user.Email = newEmail
user3, err := th.App.UpdateUser(user, false)
require.NotNil(t, err)
assert.Equal(t, err.Id, "store.sql_user.update.email_taken.app_error")
assert.Equal(t, err.Id, "app.user.save.email_exists.app_error")
assert.Nil(t, user3)
})
}
@@ -1457,3 +1457,37 @@ func TestDeactivateMfa(t *testing.T) {
require.Nil(t, err)
})
}
func TestPatchUser(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
testUser := th.CreateUser()
defer th.App.PermanentDeleteUser(testUser)
t.Run("Patch with a username already exists", func(t *testing.T) {
_, err := th.App.PatchUser(testUser.Id, &model.UserPatch{
Username: model.NewString(th.BasicUser.Username),
}, true)
require.NotNil(t, err)
require.Equal(t, "app.user.save.username_exists.app_error", err.Id)
})
t.Run("Patch with a email already exists", func(t *testing.T) {
_, err := th.App.PatchUser(testUser.Id, &model.UserPatch{
Email: model.NewString(th.BasicUser.Email),
}, true)
require.NotNil(t, err)
require.Equal(t, "app.user.save.email_exists.app_error", err.Id)
})
t.Run("Patch username with a new username", func(t *testing.T) {
_, err := th.App.PatchUser(testUser.Id, &model.UserPatch{
Username: model.NewString(model.NewId()),
}, true)
require.Nil(t, err)
})
}

View File

@@ -147,10 +147,6 @@
"id": "system.message.name",
"translation": "Система"
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Тази ел.поща вече е заета. Моля, изберете друга."
},
{
"id": "store.sql_user.get_for_login.app_error",
"translation": "Не може да се намери съществуващ профил, отговарящ на вашите идентификационни данни. Този екип може да изисква покана от собственика на екипа, за да се присъедините."

View File

@@ -4842,10 +4842,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Konnte kein Konto mit den angegeben Zugangsdaten finden. Dieses Team erfordert eventuell eine Einladung vom Teambesitzer, um beizutreten."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Diese E-Mail-Adresse wird bereits genutzt. Bitte eine andere wählen."
},
{
"id": "system.message.name",
"translation": "System"

View File

@@ -9102,10 +9102,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Unable to find an existing account matching your credentials. This team may require an invite from the team owner to join."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "This email is already taken. Please choose another."
},
{
"id": "system.message.name",
"translation": "System"

View File

@@ -4842,10 +4842,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "No se puede encontrar una cuenta existente con tus credenciales. Es posible que requieras una invitación por parte del dueño del equipo para poder unirte."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Este correo electrónico ya está siendo utilizado. Por favor escoge otro."
},
{
"id": "system.message.name",
"translation": "Sistema"

View File

@@ -4842,10 +4842,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Impossible de trouver un compte existant correspondant à vos identifiants. Cette équipe nécessite peut-être une invitation de la part du propriétaire pour pouvoir la rejoindre."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Cette adresse e-mail est déjà utilisée. Veuillez en choisir une autre."
},
{
"id": "system.message.name",
"translation": "Système"

View File

@@ -4842,10 +4842,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Non è stato possibile trovare un account con le credenziali fornite. Potrebbe essere necessario disporre di un invito da parte del proprietario del gruppo per l'accesso."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Questo indirizzo email è già in uso. Sceglierne un altro."
},
{
"id": "system.message.name",
"translation": "Sistema"

View File

@@ -4837,10 +4837,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "あなたの認証情報に合致する既存のアカウントを見付けられませんでした。このチームに参加するには、チームのオーナーから招待を受ける必要があります。"
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "この電子メールアドレスは既に使用されています。他の電子メールアドレスを指定してください。"
},
{
"id": "system.message.name",
"translation": "システム"

View File

@@ -4837,10 +4837,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "We couldn't find an existing account matching your credentials. This team may require an invite from the team owner to join."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "This email is already taken. Please choose another."
},
{
"id": "system.message.name",
"translation": "시스템"

View File

@@ -4842,10 +4842,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "We kunnen geen bestaand account vinden met de gebruikersnaam voor dit team. Het kan zijn dat een uitnodiging voor het team nodig is om lid te worden."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Dit e-mail adres is reeds in gebruik. Kies aub een andere."
},
{
"id": "system.message.name",
"translation": "Systeem"

View File

@@ -4847,10 +4847,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Nie można znaleźć istniejącego konta pasującego do poświadczeń. Ten zespół może wymagać zaproszenia od właściciela zespołu do dołączenia."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Ten adres e-mail jest już zajęty. Proszę wybrać inny."
},
{
"id": "system.message.name",
"translation": "System"

View File

@@ -4842,10 +4842,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Não foi possível encontrar uma conta correspondente a suas credenciais. Esta equipe pode exigir um convite do dono da equipe para participar."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Este email já foi utilizado. Por favor escolha outro."
},
{
"id": "system.message.name",
"translation": "Sistema"

View File

@@ -4847,10 +4847,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Nu s-a putut găsi un cont existent care să corespundă acreditărilor dvs. Această echipă poate solicita o invitație din partea proprietarului echipei să se alăture."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Acest e-mail este deja luate. Vă rugăm să alegeţi o altă."
},
{
"id": "system.message.name",
"translation": "Sistem"

View File

@@ -4847,10 +4847,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Не удалось найти действительную учетную запись с соответствующими учетными данными. Эта команда может требовать приглашения от владельца команды для присоединения."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Этот e-mail уже зарегистрирован, выберите другой."
},
{
"id": "system.message.name",
"translation": "Система"

View File

@@ -147,10 +147,6 @@
"id": "system.message.name",
"translation": "System"
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Den här e-postadressen används redan. Välj en annan."
},
{
"id": "store.sql_user.get_for_login.app_error",
"translation": "Kan inte hitta ett existerande konto som matchar din autentisering. Denna grupp kan behöva en inbjudan av ägaren till gruppen för att gå med."

View File

@@ -4842,10 +4842,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Bu takım için kimlik doğrulama bilgilerinizle eşleşen var olan bir hesap bulunamadı. Bu takıma katılmak için takım yöneticisinin çağrı göndermesi gerekiyor olabilir."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Bu e-posta adresi zaten alınmış. Lütfen başka bir adres seçin."
},
{
"id": "system.message.name",
"translation": "Sistem"

View File

@@ -4847,10 +4847,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "Не вдалося знайти дійсний обліковий запис з відповідними обліковими даними. Ця команда може вимагати запрошення від власника команди для приєднання."
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "Цей e-mail вже зареєстрований, виберіть інший."
},
{
"id": "system.message.name",
"translation": "Система"

View File

@@ -4837,10 +4837,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "未找到符合您的凭证的帐号。此团队或许需要从团队拥有者获得邀请才可加入。"
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "该邮箱已被使用。请重新选择。"
},
{
"id": "system.message.name",
"translation": "系统"

View File

@@ -4837,10 +4837,6 @@
"id": "store.sql_user.get_for_login.app_error",
"translation": "找不到符合您的認證之帳號,此團隊需要從團隊擁有者取得邀請才可加入。"
},
{
"id": "store.sql_user.update.email_taken.app_error",
"translation": "這個電子郵件已經被使用。請選擇其他的。"
},
{
"id": "system.message.name",
"translation": "系統"

View File

@@ -210,10 +210,10 @@ func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) (*model.
count, err := us.GetMaster().Update(user)
if err != nil {
if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique"}) {
return nil, store.NewErrInvalidInput("User", "id", user.Id)
return nil, store.NewErrConflict("Email", err, user.Email)
}
if IsUniqueConstraintError(err, []string{"Username", "users_username_key", "idx_users_username_unique"}) {
return nil, store.NewErrInvalidInput("User", "id", user.Id)
return nil, store.NewErrConflict("Username", err, user.Username)
}
return nil, errors.Wrapf(err, "failed to update User with userId=%s", user.Id)
}