diff --git a/app/bot.go b/app/bot.go index 4809cd17a9..3462daad28 100644 --- a/app/bot.go +++ b/app/bot.go @@ -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) } diff --git a/app/bot_test.go b/app/bot_test.go index 5fd5e41644..6088e1eb99 100644 --- a/app/bot_test.go +++ b/app/bot_test.go @@ -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) }) } diff --git a/app/user.go b/app/user.go index 2f476dbb0b..2bd2779207 100644 --- a/app/user.go +++ b/app/user.go @@ -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) } diff --git a/app/user_test.go b/app/user_test.go index 608afd828f..d9b1fa3385 100644 --- a/app/user_test.go +++ b/app/user_test.go @@ -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) + }) +} diff --git a/i18n/bg.json b/i18n/bg.json index eb59ad9d70..88e93cf1d1 100644 --- a/i18n/bg.json +++ b/i18n/bg.json @@ -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": "Не може да се намери съществуващ профил, отговарящ на вашите идентификационни данни. Този екип може да изисква покана от собственика на екипа, за да се присъедините." diff --git a/i18n/de.json b/i18n/de.json index 5cbe8aa2c9..05944dc32c 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -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" diff --git a/i18n/en.json b/i18n/en.json index 07532a7d03..6c689e0029 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -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" diff --git a/i18n/es.json b/i18n/es.json index e9b7eaa0df..e8da989006 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -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" diff --git a/i18n/fr.json b/i18n/fr.json index 6ef5c84902..020b356f37 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -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" diff --git a/i18n/it.json b/i18n/it.json index 61c2f9f2f3..2db5756d47 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -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" diff --git a/i18n/ja.json b/i18n/ja.json index 96e9b95cf5..3b63726a35 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -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": "システム" diff --git a/i18n/ko.json b/i18n/ko.json index 5fe37ec9ad..102775e875 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -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": "시스템" diff --git a/i18n/nl.json b/i18n/nl.json index 7de3f217c5..2356fd8b0e 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -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" diff --git a/i18n/pl.json b/i18n/pl.json index c8afa466a1..696ef75743 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -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" diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json index 2836687e3c..46edbd8c46 100644 --- a/i18n/pt-BR.json +++ b/i18n/pt-BR.json @@ -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" diff --git a/i18n/ro.json b/i18n/ro.json index 47c620ca44..acb307fb10 100644 --- a/i18n/ro.json +++ b/i18n/ro.json @@ -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" diff --git a/i18n/ru.json b/i18n/ru.json index 68e8e2a317..c2bd12fdd6 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -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": "Система" diff --git a/i18n/sv.json b/i18n/sv.json index d9d91d8fcc..dc5d45c746 100644 --- a/i18n/sv.json +++ b/i18n/sv.json @@ -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." diff --git a/i18n/tr.json b/i18n/tr.json index 94ee4fa08f..4f82bef133 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -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" diff --git a/i18n/uk.json b/i18n/uk.json index 1a4b1477db..cb9dec102e 100644 --- a/i18n/uk.json +++ b/i18n/uk.json @@ -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": "Система" diff --git a/i18n/zh-CN.json b/i18n/zh-CN.json index da422464a3..de65131885 100644 --- a/i18n/zh-CN.json +++ b/i18n/zh-CN.json @@ -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": "系统" diff --git a/i18n/zh-TW.json b/i18n/zh-TW.json index 48bfe5e02d..00592d8428 100644 --- a/i18n/zh-TW.json +++ b/i18n/zh-TW.json @@ -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": "系統" diff --git a/store/sqlstore/user_store.go b/store/sqlstore/user_store.go index 515538a908..ed390438d7 100644 --- a/store/sqlstore/user_store.go +++ b/store/sqlstore/user_store.go @@ -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) }