diff --git a/pkg/api/forget_passwords.go b/pkg/api/forget_passwords.go index bb9778e4..34afa5a1 100644 --- a/pkg/api/forget_passwords.go +++ b/pkg/api/forget_passwords.go @@ -131,7 +131,7 @@ func (a *ForgetPasswordsApi) UserResetPasswordHandler(c *core.Context) (interfac Password: request.Password, } - _, err = a.users.UpdateUser(c, userNew, false) + _, _, err = a.users.UpdateUser(c, userNew, false) if err != nil { log.ErrorfWithRequestId(c, "[forget_passwords.UserResetPasswordHandler] failed to update user \"uid:%d\", because %s", user.Uid, err.Error()) diff --git a/pkg/api/users.go b/pkg/api/users.go index 68103862..6c965415 100644 --- a/pkg/api/users.go +++ b/pkg/api/users.go @@ -324,13 +324,17 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.Context) (interface{}, *errs return nil, errs.ErrNothingWillBeUpdated } - keyProfileUpdated, err := a.users.UpdateUser(c, userNew, modifyUserLanguage) + keyProfileUpdated, emailSetToUnverified, err := a.users.UpdateUser(c, userNew, modifyUserLanguage) if err != nil { log.ErrorfWithRequestId(c, "[users.UserUpdateProfileHandler] failed to update user \"uid:%d\", because %s", user.Uid, err.Error()) return nil, errs.Or(err, errs.ErrOperationFailed) } + if emailSetToUnverified { + user.EmailVerified = false + } + log.InfofWithRequestId(c, "[users.UserUpdateProfileHandler] user \"uid:%d\" has updated successfully", user.Uid) resp := &models.UserProfileUpdateResponse{ diff --git a/pkg/cli/user_data.go b/pkg/cli/user_data.go index 503bf3d9..b9122e1b 100644 --- a/pkg/cli/user_data.go +++ b/pkg/cli/user_data.go @@ -145,7 +145,7 @@ func (l *UserDataCli) ModifyUserPassword(c *cli.Context, username string, passwo Password: password, } - _, err = l.users.UpdateUser(nil, userNew, false) + _, _, err = l.users.UpdateUser(nil, userNew, false) if err != nil { log.BootErrorf("[user_data.ModifyUserPassword] failed to update user \"%s\" password, because %s", user.Username, err.Error()) diff --git a/pkg/models/user.go b/pkg/models/user.go index 336ee440..681d0ecc 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -89,6 +89,7 @@ type UserBasicInfo struct { ShortDateFormat ShortDateFormat `json:"shortDateFormat"` LongTimeFormat LongTimeFormat `json:"longTimeFormat"` ShortTimeFormat ShortTimeFormat `json:"shortTimeFormat"` + EmailVerified bool `json:"emailVerified"` } // UserLoginRequest represents all parameters of user login request @@ -227,6 +228,7 @@ func (u *User) ToUserBasicInfo() *UserBasicInfo { ShortDateFormat: u.ShortDateFormat, LongTimeFormat: u.LongTimeFormat, ShortTimeFormat: u.ShortTimeFormat, + EmailVerified: u.EmailVerified, } } diff --git a/pkg/services/users.go b/pkg/services/users.go index 6a9fb1f8..91a0bb8e 100644 --- a/pkg/services/users.go +++ b/pkg/services/users.go @@ -168,29 +168,32 @@ func (s *UserService) CreateUser(c *core.Context, user *models.User) error { } // UpdateUser saves an existed user model to database -func (s *UserService) UpdateUser(c *core.Context, user *models.User, modifyUserLanguage bool) (keyProfileUpdated bool, err error) { +func (s *UserService) UpdateUser(c *core.Context, user *models.User, modifyUserLanguage bool) (keyProfileUpdated bool, emailSetToUnverified bool, err error) { if user.Uid <= 0 { - return false, errs.ErrUserIdInvalid + return false, false, errs.ErrUserIdInvalid } updateCols := make([]string, 0, 8) now := time.Now().Unix() keyProfileUpdated = false + emailSetToUnverified = false if user.Email != "" { exists, err := s.ExistsEmail(c, user.Email) if err != nil { - return false, err + return false, false, err } else if exists { - return false, errs.ErrUserEmailAlreadyExists + return false, false, errs.ErrUserEmailAlreadyExists } user.EmailVerified = false updateCols = append(updateCols, "email") updateCols = append(updateCols, "email_verified") + + emailSetToUnverified = true } if user.Password != "" { @@ -256,10 +259,10 @@ func (s *UserService) UpdateUser(c *core.Context, user *models.User, modifyUserL }) if err != nil { - return false, err + return false, false, err } - return keyProfileUpdated, nil + return keyProfileUpdated, emailSetToUnverified, nil } // UpdateUserLastLoginTime updates the last login time field diff --git a/src/locales/en.js b/src/locales/en.js index e5727280..dd96446d 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -1066,6 +1066,8 @@ export default { 'Basic Settings': 'Basic Settings', 'Security Settings': 'Security Settings', 'Two-Factor Authentication Settings': 'Two-Factor Authentication Settings', + '(Verified)': '(Verified)', + '(Unverified)': '(Unverified)', 'Email has been verified': 'Email has been verified', 'Email has not been verified': 'Email has not been verified', 'Username:': 'Username:', diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js index 086a3dd3..dde31e74 100644 --- a/src/locales/zh_Hans.js +++ b/src/locales/zh_Hans.js @@ -1066,6 +1066,8 @@ export default { 'Basic Settings': '基本设置', 'Security Settings': '安全设置', 'Two-Factor Authentication Settings': '两步验证设置', + '(Verified)': '(已验证)', + '(Unverified)': '(未验证)', 'Email has been verified': '邮箱地址已验证', 'Email has not been verified': '邮箱地址未验证', 'Username:': '用户名:', diff --git a/src/views/desktop/user/settings/tabs/UserBasicSettingTab.vue b/src/views/desktop/user/settings/tabs/UserBasicSettingTab.vue index 20ba9a96..7d1752d3 100644 --- a/src/views/desktop/user/settings/tabs/UserBasicSettingTab.vue +++ b/src/views/desktop/user/settings/tabs/UserBasicSettingTab.vue @@ -18,15 +18,20 @@ -
+
{{ $t('Username:') }} {{ oldProfile.username }}
-
- {{ $t('Email has been verified') }} - {{ $t('Email has not been verified') }} +
+ {{ $t('Email has been verified') }} + {{ $t('Email has not been verified') }} + + {{ $t('Resend Validation Email') }} + +
@@ -270,6 +275,7 @@ export default { }, emailVerified: false, loading: true, + resending: false, saving: false, icons: { user: mdiAccount @@ -377,7 +383,6 @@ export default { Promise.all(promises).then(responses => { const profile = responses[1]; self.setCurrentUserProfile(profile); - self.emailVerified = profile.emailVerified; self.loading = false; }).catch(error => { self.oldProfile.nickname = ''; @@ -428,10 +433,28 @@ export default { reset() { this.setCurrentUserProfile(this.oldProfile); }, + resendVerifyEmail() { + const self = this; + + self.resending = true; + + self.rootStore.resendVerifyEmailByLoginedUser().then(() => { + self.resending = false; + self.$refs.snackbar.showMessage('Validation email has been sent'); + }).catch(error => { + self.resending = false; + + if (!error.processed) { + self.$refs.snackbar.showError(error); + } + }); + }, getNameByKeyValue(src, value, keyField, nameField, defaultName) { return getNameByKeyValue(src, value, keyField, nameField, defaultName); }, setCurrentUserProfile(profile) { + this.emailVerified = profile.emailVerified; + this.oldProfile.username = profile.username; this.oldProfile.email = profile.email; this.oldProfile.nickname = profile.nickname; diff --git a/src/views/mobile/users/UserProfilePage.vue b/src/views/mobile/users/UserProfilePage.vue index 4a78df55..ce05befa 100644 --- a/src/views/mobile/users/UserProfilePage.vue +++ b/src/views/mobile/users/UserProfilePage.vue @@ -3,7 +3,8 @@ - + + @@ -53,7 +54,7 @@ type="email" autocomplete="email" clear-button - :label="$t('E-mail')" + :label="$t('E-mail') + ' ' + (emailVerified ? $t('(Verified)') : $t('(Unverified)'))" :placeholder="$t('Your email address')" v-model:value="newProfile.email" > @@ -208,6 +209,17 @@ + + + {{ $t('Resend Validation Email') }} + + + {{ $t('Cancel') }} + + + self.resending); + + self.rootStore.resendVerifyEmailByLoginedUser().then(() => { + self.resending = false; + self.$hideLoading(); + + self.$toast('Validation email has been sent'); + }).catch(error => { + self.resending = false; + self.$hideLoading(); + + if (!error.processed) { + self.$toast(error.message || error); + } + }); + }, getNameByKeyValue(src, value, keyField, nameField, defaultName) { return getNameByKeyValue(src, value, keyField, nameField, defaultName); }, @@ -460,6 +495,8 @@ export default { return this.$locale.getCurrencyName(currencyCode); }, setCurrentUserProfile(profile) { + this.emailVerified = profile.emailVerified; + this.oldProfile.email = profile.email; this.oldProfile.nickname = profile.nickname; this.oldProfile.defaultAccountId = profile.defaultAccountId;