support reset password by email reset link

This commit is contained in:
MaysWind
2023-08-26 23:37:02 +08:00
parent c66bc62c41
commit f31ef1649f
42 changed files with 1298 additions and 30 deletions
+16
View File
@@ -2,6 +2,8 @@ package services
import (
"github.com/mayswind/ezbookkeeping/pkg/datastore"
"github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/mail"
"github.com/mayswind/ezbookkeeping/pkg/settings"
"github.com/mayswind/ezbookkeeping/pkg/uuid"
)
@@ -36,6 +38,20 @@ func (s *ServiceUsingConfig) CurrentConfig() *settings.Config {
return s.container.Current
}
// ServiceUsingMailer represents a service that need to use mailer
type ServiceUsingMailer struct {
container *mail.MailerContainer
}
// SendMail sends an email according to argument
func (s *ServiceUsingMailer) SendMail(message *mail.MailMessage) error {
if s.container.Current == nil {
return errs.ErrSmtpServerNotEnabled
}
return s.container.Current.SendMail(message)
}
// ServiceUsingUuid represents a service that need to use uuid
type ServiceUsingUuid struct {
container *uuid.UuidContainer
+81
View File
@@ -0,0 +1,81 @@
package services
import (
"bytes"
"fmt"
"net/url"
"github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/locales"
"github.com/mayswind/ezbookkeeping/pkg/mail"
"github.com/mayswind/ezbookkeeping/pkg/models"
"github.com/mayswind/ezbookkeeping/pkg/settings"
"github.com/mayswind/ezbookkeeping/pkg/templates"
)
const passwordResetUrlFormat = "%sdesktop/#/resetpassword?token=%s"
// ForgetPasswordService represents forget password service
type ForgetPasswordService struct {
ServiceUsingConfig
ServiceUsingMailer
}
// Initialize a forget password service singleton instance
var (
ForgetPasswords = &ForgetPasswordService{
ServiceUsingConfig: ServiceUsingConfig{
container: settings.Container,
},
ServiceUsingMailer: ServiceUsingMailer{
container: mail.Container,
},
}
)
// SendPasswordResetEmail sends password reset email according to specified parameters
func (s *ForgetPasswordService) SendPasswordResetEmail(user *models.User, passwordResetToken string) error {
if !s.CurrentConfig().EnableSmtp {
return errs.ErrSmtpServerNotEnabled
}
localeTextItems := locales.GetLocaleTextItems(user.Language)
forgetPasswordTextItems := localeTextItems.ForgetPasswordMailTextItems
expireTimeInMinutes := s.CurrentConfig().ForgetPasswordTokenExpiredTimeDuration.Minutes()
passwordResetUrl := fmt.Sprintf(passwordResetUrlFormat, s.CurrentConfig().RootUrl, url.QueryEscape(passwordResetToken))
tmpl, err := templates.GetTemplate("email/password_reset")
if err != nil {
return err
}
templateParams := map[string]interface{}{
"ForgetPasswordMail": map[string]interface{}{
"Title": forgetPasswordTextItems.Title,
"Salutation": fmt.Sprintf(forgetPasswordTextItems.SalutationFormat, user.Nickname),
"DescriptionAboveBtn": forgetPasswordTextItems.DescriptionAboveBtn,
"ResetPasswordUrl": passwordResetUrl,
"ResetPassword": forgetPasswordTextItems.ResetPassword,
"DescriptionBelowBtn": fmt.Sprintf(forgetPasswordTextItems.DescriptionBelowBtnFormat, expireTimeInMinutes),
},
}
var bodyBuffer bytes.Buffer
err = tmpl.Execute(&bodyBuffer, templateParams)
if err != nil {
return err
}
message := &mail.MailMessage{
To: user.Email,
Subject: forgetPasswordTextItems.Title,
Body: bodyBuffer.String(),
}
err = s.SendMail(message)
return err
}
+5
View File
@@ -88,6 +88,11 @@ func (s *TokenService) CreateRequire2FAToken(user *models.User, ctx *core.Contex
return s.createToken(user, core.USER_TOKEN_TYPE_REQUIRE_2FA, s.getUserAgent(ctx), s.CurrentConfig().TemporaryTokenExpiredTimeDuration)
}
// CreatePasswordResetToken generates a new password reset token and saves to database
func (s *TokenService) CreatePasswordResetToken(user *models.User, ctx *core.Context) (string, *core.UserTokenClaims, error) {
return s.createToken(user, core.USER_TOKEN_TYPE_RESET_PASSWORD, s.getUserAgent(ctx), s.CurrentConfig().ForgetPasswordTokenExpiredTimeDuration)
}
// DeleteToken deletes given token from database
func (s *TokenService) DeleteToken(tokenRecord *models.TokenRecord) error {
if tokenRecord.Uid <= 0 {