Skip to content

Commit

Permalink
fix: primary email cannot be activated
Browse files Browse the repository at this point in the history
* Primary email should be activated together with user account when
'RegisterEmailConfirm' is enabled.

* To fix the existing error state. When 'RegisterEmailConfirm' is enabled, the
admin should have permission to modify the activations status of user email.
And the user should be allowed to send activation to primary email.

* Only judge whether email is primary from email_address table.

Signed-off-by: Meano <meanocat@gmail.com>
  • Loading branch information
Meano committed Jul 12, 2021
1 parent 522b720 commit 7669ff8
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 38 deletions.
27 changes: 13 additions & 14 deletions models/user_mail.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,8 @@ func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error)
}

// ActivateUserEmail will change the activated state of an email address,
// either primary (in the user table) or secondary (in the email_address table)
func ActivateUserEmail(userID int64, email string, primary, activate bool) (err error) {
// either primary or secondary (all in the email_address table)
func ActivateUserEmail(userID int64, email string, activate bool) (err error) {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
Expand Down Expand Up @@ -397,24 +397,23 @@ func ActivateUserEmail(userID int64, email string, primary, activate bool) (err
return fmt.Errorf("updateActivation(): %v", err)
}

if primary {
// Activate/deactivate a user's primary email address
// Activate/deactivate a user's primary email address and account
if addr.IsPrimary {
user := User{ID: userID, Email: email}
if has, err := sess.Get(&user); err != nil {
return err
} else if !has {
return fmt.Errorf("no such user: %d (%s)", userID, email)
}
if user.IsActive == activate {
// Already in the desired state; no action
return nil
}
user.IsActive = activate
if user.Rands, err = GetUserSalt(); err != nil {
return fmt.Errorf("generate salt: %v", err)
}
if err = updateUserCols(sess, &user, "is_active", "rands"); err != nil {
return fmt.Errorf("updateUserCols(): %v", err)
// The user's activation state should synchronized with the primary email
if user.IsActive != activate {
user.IsActive = activate
if user.Rands, err = GetUserSalt(); err != nil {
return fmt.Errorf("generate salt: %v", err)
}
if err = updateUserCols(sess, &user, "is_active", "rands"); err != nil {
return fmt.Errorf("updateUserCols(): %v", err)
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions routers/web/admin/emails.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ func ActivateEmail(ctx *context.Context) {

log.Info("Changing activation for User ID: %d, email: %s, primary: %v to %v", uid, email, primary, activate)

if err := models.ActivateUserEmail(uid, email, primary, activate); err != nil {
log.Error("ActivateUserEmail(%v,%v,%v,%v): %v", uid, email, primary, activate, err)
if err := models.ActivateUserEmail(uid, email, activate); err != nil {
log.Error("ActivateUserEmail(%v,%v,%v): %v", uid, email, activate, err)
if models.IsErrEmailAlreadyUsed(err) {
ctx.Flash.Error(ctx.Tr("admin.emails.duplicate_active"))
} else {
Expand Down
4 changes: 4 additions & 0 deletions routers/web/user/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,10 @@ func handleAccountActivation(ctx *context.Context, user *models.User) {
return
}

if err := models.ActivateUserEmail(user.ID, user.Email, true); err != nil {
log.Error(fmt.Sprintf("Error active user mail: %v", err))
}

log.Trace("User activated: %s", user.Name)

if err := ctx.Session.Set("uid", user.ID); err != nil {
Expand Down
43 changes: 22 additions & 21 deletions routers/web/user/setting/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,35 +107,36 @@ func EmailPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if ctx.Query("id") == "PRIMARY" {
if ctx.User.IsActive {

id := ctx.QueryInt64("id")
email, err := models.GetEmailAddressByID(ctx.User.ID, id)
if err != nil {
log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.User.ID, id, err)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if email == nil {
log.Error("Send activation: EmailAddress not found; user:%d, id: %d", ctx.User.ID, id)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if email.IsActivated {
log.Error("Send activation: email not set for activation")
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if email.IsPrimary {
if ctx.User.IsActive && !setting.Service.RegisterEmailConfirm {
log.Error("Send activation: email not set for activation")
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
// Only fired when the primary email is inactive (Wrong state)
mailer.SendActivateAccountMail(ctx.Locale, ctx.User)
address = ctx.User.Email
} else {
id := ctx.QueryInt64("id")
email, err := models.GetEmailAddressByID(ctx.User.ID, id)
if err != nil {
log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.User.ID, id, err)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if email == nil {
log.Error("Send activation: EmailAddress not found; user:%d, id: %d", ctx.User.ID, id)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
if email.IsActivated {
log.Error("Send activation: email not set for activation")
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
mailer.SendActivateEmailMail(ctx.User, email)
address = email.Email
}
address = email.Email

if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
log.Error("Set cache(MailResendLimit) fail: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion templates/user/settings/account.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
<form action="{{AppSubUrl}}/user/settings/account/email" method="post">
{{$.CsrfTokenHtml}}
<input name="_method" type="hidden" value="SENDACTIVATION">
<input name="id" type="hidden" value="{{if .IsPrimary}}PRIMARY{{else}}{{.ID}}{{end}}">
<input name="id" type="hidden" value="{{.ID}}">
{{if $.ActivationsPending}}
<button disabled class="ui blue tiny button">{{$.i18n.Tr "settings.activations_pending"}}</button>
{{else}}
Expand Down

0 comments on commit 7669ff8

Please sign in to comment.