Skip to content

Commit d29a0fc

Browse files
authored
Fix user primary email changed (#17840)
1 parent 04517e1 commit d29a0fc

File tree

6 files changed

+58
-14
lines changed

6 files changed

+58
-14
lines changed

models/user.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,18 +1072,46 @@ func validateUser(u *User) error {
10721072
return ValidateEmail(u.Email)
10731073
}
10741074

1075-
func updateUser(e Engine, u *User) error {
1075+
func updateUser(e Engine, u *User, changePrimaryEmail bool) error {
10761076
if err := validateUser(u); err != nil {
10771077
return err
10781078
}
10791079

1080+
if changePrimaryEmail {
1081+
var emailAddress EmailAddress
1082+
has, err := e.Where("lower_email=?", strings.ToLower(u.Email)).Get(&emailAddress)
1083+
if err != nil {
1084+
return err
1085+
}
1086+
if !has {
1087+
// 1. Update old primary email
1088+
if _, err = e.Where("uid=? AND is_primary=?", u.ID, true).Cols("is_primary").Update(&EmailAddress{
1089+
IsPrimary: false,
1090+
}); err != nil {
1091+
return err
1092+
}
1093+
1094+
emailAddress.Email = u.Email
1095+
emailAddress.UID = u.ID
1096+
emailAddress.IsActivated = true
1097+
emailAddress.IsPrimary = true
1098+
if _, err := e.Insert(&emailAddress); err != nil {
1099+
return err
1100+
}
1101+
} else if _, err := e.ID(emailAddress).Cols("is_primary").Update(&EmailAddress{
1102+
IsPrimary: true,
1103+
}); err != nil {
1104+
return err
1105+
}
1106+
}
1107+
10801108
_, err := e.ID(u.ID).AllCols().Update(u)
10811109
return err
10821110
}
10831111

10841112
// UpdateUser updates user's information.
1085-
func UpdateUser(u *User) error {
1086-
return updateUser(x, u)
1113+
func UpdateUser(u *User, changePrimaryEmail bool) error {
1114+
return updateUser(x, u, changePrimaryEmail)
10871115
}
10881116

10891117
// UpdateUserCols update user according special columns
@@ -1112,7 +1140,7 @@ func UpdateUserSetting(u *User) (err error) {
11121140
return err
11131141
}
11141142
}
1115-
if err = updateUser(sess, u); err != nil {
1143+
if err = updateUser(sess, u, false); err != nil {
11161144
return err
11171145
}
11181146
return sess.Commit()

models/user_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,17 +475,17 @@ func TestUpdateUser(t *testing.T) {
475475
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
476476

477477
user.KeepActivityPrivate = true
478-
assert.NoError(t, UpdateUser(user))
478+
assert.NoError(t, UpdateUser(user, false))
479479
user = AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
480480
assert.True(t, user.KeepActivityPrivate)
481481

482482
setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, false}
483483
user.KeepActivityPrivate = false
484484
user.Visibility = structs.VisibleTypePrivate
485-
assert.Error(t, UpdateUser(user))
485+
assert.Error(t, UpdateUser(user, false))
486486
user = AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
487487
assert.True(t, user.KeepActivityPrivate)
488488

489489
user.Email = "no [email protected]"
490-
assert.Error(t, UpdateUser(user))
490+
assert.Error(t, UpdateUser(user, true))
491491
}

routers/api/v1/admin/user.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"errors"
1010
"fmt"
1111
"net/http"
12+
"strings"
1213

1314
"code.gitea.io/gitea/models"
1415
"code.gitea.io/gitea/modules/context"
@@ -199,12 +200,20 @@ func EditUser(ctx *context.APIContext) {
199200
if form.FullName != nil {
200201
u.FullName = *form.FullName
201202
}
203+
var emailChanged bool
202204
if form.Email != nil {
203-
u.Email = *form.Email
204-
if len(u.Email) == 0 {
205+
email := strings.TrimSpace(*form.Email)
206+
if len(email) == 0 {
205207
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("email is not allowed to be empty string"))
206208
return
207209
}
210+
if err := models.ValidateEmail(email); err != nil {
211+
ctx.InternalServerError(err)
212+
return
213+
}
214+
215+
emailChanged = !strings.EqualFold(u.Email, email)
216+
u.Email = email
208217
}
209218
if form.Website != nil {
210219
u.Website = *form.Website
@@ -243,7 +252,7 @@ func EditUser(ctx *context.APIContext) {
243252
u.IsRestricted = *form.Restricted
244253
}
245254

246-
if err := models.UpdateUser(u); err != nil {
255+
if err := models.UpdateUser(u, emailChanged); err != nil {
247256
if models.IsErrEmailAlreadyUsed(err) || models.IsErrEmailInvalid(err) {
248257
ctx.Error(http.StatusUnprocessableEntity, "", err)
249258
} else {

routers/api/v1/user/settings.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func UpdateUserSettings(ctx *context.APIContext) {
7474
ctx.User.KeepActivityPrivate = *form.HideActivity
7575
}
7676

77-
if err := models.UpdateUser(ctx.User); err != nil {
77+
if err := models.UpdateUser(ctx.User, false); err != nil {
7878
ctx.InternalServerError(err)
7979
return
8080
}

routers/web/admin/users.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,11 @@ func EditUserPost(ctx *context.Context) {
273273
ctx.RenderWithErr(errMsg, tplUserNew, &form)
274274
return
275275
}
276+
if err := models.ValidateEmail(form.Email); err != nil {
277+
ctx.Data["Err_Email"] = true
278+
ctx.RenderWithErr(ctx.Tr("form.email_error"), tplUserNew, &form)
279+
return
280+
}
276281
if u.Salt, err = models.GetUserSalt(); err != nil {
277282
ctx.ServerError("UpdateUser", err)
278283
return
@@ -307,7 +312,9 @@ func EditUserPost(ctx *context.Context) {
307312

308313
u.LoginName = form.LoginName
309314
u.FullName = form.FullName
310-
u.Email = form.Email
315+
email := strings.TrimSpace(form.Email)
316+
emailChanged := !strings.EqualFold(u.Email, email)
317+
u.Email = email
311318
u.Website = form.Website
312319
u.Location = form.Location
313320
u.MaxRepoCreation = form.MaxRepoCreation
@@ -327,7 +334,7 @@ func EditUserPost(ctx *context.Context) {
327334
u.ProhibitLogin = form.ProhibitLogin
328335
}
329336

330-
if err := models.UpdateUser(u); err != nil {
337+
if err := models.UpdateUser(u, emailChanged); err != nil {
331338
if models.IsErrEmailAlreadyUsed(err) {
332339
ctx.Data["Err_Email"] = true
333340
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form)

routers/web/org/setting.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func SettingsPost(ctx *context.Context) {
9696
visibilityChanged := form.Visibility != org.Visibility
9797
org.Visibility = form.Visibility
9898

99-
if err := models.UpdateUser(org); err != nil {
99+
if err := models.UpdateUser(org, false); err != nil {
100100
ctx.ServerError("UpdateUser", err)
101101
return
102102
}

0 commit comments

Comments
 (0)