11package services
22
33import (
4+ "bbs-go/internal/models"
45 "bbs-go/internal/models/constants"
56 "bbs-go/internal/models/dto"
67 "bbs-go/internal/pkg/bbsurls"
@@ -24,14 +25,15 @@ import (
2425 "gorm.io/gorm"
2526
2627 "bbs-go/internal/cache"
27-
28- "bbs-go/internal/models"
2928 "bbs-go/internal/repositories"
3029)
3130
3231// 邮箱验证邮件有效期(小时)
3332const emailVerifyExpireHour = 24
3433
34+ // 密码重置邮件有效期(小时)
35+ const passwordResetExpireHour = 1
36+
3537var UserService = newUserService ()
3638
3739func newUserService () * userService {
@@ -206,13 +208,24 @@ func (s *userService) SignUp(username, email, nickname, password, rePassword str
206208 // 验证密码
207209 err := validate .IsValidPassword (password , rePassword )
208210 if err != nil {
209- return nil , err
211+ // 根据不同的验证错误返回对应的多语言化消息
212+ if strings .Contains (err .Error (), "密码过于简单" ) {
213+ return nil , errors .New (locales .Get ("errors.password_simple" ))
214+ } else if strings .Contains (err .Error (), "密码长度不能超过128" ) {
215+ return nil , errors .New (locales .Get ("errors.password_length_invalid" ))
216+ } else if strings .Contains (err .Error (), "两次输入密码不匹配" ) {
217+ return nil , errors .New (locales .Get ("errors.password_not_match" ))
218+ } else if strings .Contains (err .Error (), "请输入密码" ) {
219+ return nil , errors .New (locales .Get ("errors.password_empty" ))
220+ }
221+ // 默认返回密码无效的错误
222+ return nil , errors .New (locales .Get ("errors.password_empty" ))
210223 }
211224
212225 // 验证邮箱
213226 if len (email ) > 0 {
214227 if err := validate .IsEmail (email ); err != nil {
215- return nil , err
228+ return nil , errors . New ( locales . Get ( "errors.email_invalid" ))
216229 }
217230 if s .GetByEmail (email ) != nil {
218231 return nil , errors .New ("邮箱:" + email + " 已被占用" )
@@ -353,7 +366,7 @@ func (s *userService) SetUsername(userId int64, username string) error {
353366func (s * userService ) SetEmail (userId int64 , email string ) error {
354367 email = strings .TrimSpace (email )
355368 if err := validate .IsEmail (email ); err != nil {
356- return err
369+ return errors . New ( locales . Get ( "errors.email_invalid" ))
357370 }
358371 user := s .Get (userId )
359372 if user == nil {
@@ -366,16 +379,31 @@ func (s *userService) SetEmail(userId int64, email string) error {
366379 if s .isEmailExists (email ) {
367380 return errors .New ("邮箱:" + email + " 已被占用" )
368381 }
382+
369383 return s .Updates (userId , map [string ]interface {}{
370- "email" : email ,
384+
385+ "email" : email ,
386+
371387 "email_verified" : false ,
372388 })
389+
373390}
374391
375392// SetPassword 设置密码
376393func (s * userService ) SetPassword (userId int64 , password , rePassword string ) error {
377394 if err := validate .IsValidPassword (password , rePassword ); err != nil {
378- return err
395+ // 根据不同的验证错误返回对应的多语言化消息
396+ if strings .Contains (err .Error (), "密码过于简单" ) {
397+ return errors .New (locales .Get ("errors.password_simple" ))
398+ } else if strings .Contains (err .Error (), "密码长度不能超过128" ) {
399+ return errors .New (locales .Get ("errors.password_length_invalid" ))
400+ } else if strings .Contains (err .Error (), "两次输入密码不匹配" ) {
401+ return errors .New (locales .Get ("errors.password_not_match" ))
402+ } else if strings .Contains (err .Error (), "请输入密码" ) {
403+ return errors .New (locales .Get ("errors.password_empty" ))
404+ }
405+ // 默认返回密码无效的错误
406+ return errors .New (locales .Get ("errors.password_empty" ))
379407 }
380408 user := s .Get (userId )
381409 if len (user .Password ) > 0 {
@@ -388,7 +416,18 @@ func (s *userService) SetPassword(userId int64, password, rePassword string) err
388416// UpdatePassword 修改密码
389417func (s * userService ) UpdatePassword (userId int64 , oldPassword , password , rePassword string ) error {
390418 if err := validate .IsValidPassword (password , rePassword ); err != nil {
391- return err
419+ // 根据不同的验证错误返回对应的多语言化消息
420+ if strings .Contains (err .Error (), "密码过于简单" ) {
421+ return errors .New (locales .Get ("errors.password_simple" ))
422+ } else if strings .Contains (err .Error (), "密码长度不能超过128" ) {
423+ return errors .New (locales .Get ("errors.password_length_invalid" ))
424+ } else if strings .Contains (err .Error (), "两次输入密码不匹配" ) {
425+ return errors .New (locales .Get ("errors.password_not_match" ))
426+ } else if strings .Contains (err .Error (), "请输入密码" ) {
427+ return errors .New (locales .Get ("errors.password_empty" ))
428+ }
429+ // 默认返回密码无效的错误
430+ return errors .New (locales .Get ("errors.password_empty" ))
392431 }
393432 user := s .Get (userId )
394433
@@ -400,7 +439,8 @@ func (s *userService) UpdatePassword(userId int64, oldPassword, password, rePass
400439 return errors .New ("旧密码验证失败" )
401440 }
402441
403- return s .UpdateColumn (userId , "password" , passwd .EncodePassword (password ))
442+ password = passwd .EncodePassword (password )
443+ return s .UpdateColumn (userId , "password" , password )
404444}
405445
406446// IncrTopicCount topic_count + 1
@@ -451,7 +491,7 @@ func (s *userService) SendEmailVerifyEmail(userId int64) error {
451491 return errors .New (locales .Get ("user.email_verified" ))
452492 }
453493 if err := validate .IsEmail (user .Email .String ); err != nil {
454- return err
494+ return errors . New ( locales . Get ( "errors.email_invalid" ))
455495 }
456496 // 如果设置了邮箱白名单
457497 if emailWhitelist := SysConfigService .GetEmailWhitelist (); len (emailWhitelist ) > 0 {
@@ -633,3 +673,108 @@ func (s *userService) addScore(userId int64, score int, sourceType, sourceId, de
633673 }
634674 return err
635675}
676+
677+ // SendPasswordResetEmail 发送密码重置邮件
678+ func (s * userService ) SendPasswordResetEmail (emailStr string ) error {
679+ user := s .GetByEmail (emailStr )
680+ if user == nil {
681+ return errors .New (locales .Get ("errors.email_not_registered" ))
682+ }
683+
684+ // 生成重置令牌
685+ token := strs .UUID ()
686+ resetUrl := bbsurls .AbsUrl ("/user/reset-password?token=" + token )
687+
688+ // 准备邮件内容
689+ siteTitle := cache .SysConfigCache .GetStr (constants .SysConfigSiteTitle )
690+ subject := locales .Getf ("user.password_reset_title" , siteTitle )
691+ title := locales .Getf ("user.password_reset_title" , siteTitle )
692+ content := locales .Getf ("user.password_reset_content" , siteTitle , passwordResetExpireHour , resetUrl )
693+ link := & dto.ActionLink {Title : locales .Get ("user.password_reset_link" ), Url : resetUrl }
694+
695+ return sqls .DB ().Transaction (func (tx * gorm.DB ) error {
696+ // 保存重置令牌到数据库
697+ emailCode := & models.EmailCode {
698+ UserId : user .Id ,
699+ Email : emailStr ,
700+ Token : token ,
701+ Title : title ,
702+ Content : content ,
703+ Used : false ,
704+ CreateTime : dates .NowTimestamp (),
705+ }
706+ if err := repositories .EmailCodeRepository .Create (tx , emailCode ); err != nil {
707+ return err
708+ }
709+
710+ // 发送邮件
711+ if err := email .SendTemplateEmail (nil , emailStr , subject , title , content , "" , link ); err != nil {
712+ return err
713+ }
714+
715+ return nil
716+ })
717+ }
718+
719+ // ResetPassword 重置密码
720+ func (s * userService ) ResetPassword (token , password , rePassword string ) error {
721+ // 验证密码
722+ if err := validate .IsValidPassword (password , rePassword ); err != nil {
723+ // 根据不同的验证错误返回对应的多语言化消息
724+ if strings .Contains (err .Error (), "密码过于简单" ) {
725+ return errors .New (locales .Get ("errors.password_simple" ))
726+ } else if strings .Contains (err .Error (), "密码长度不能超过128" ) {
727+ return errors .New (locales .Get ("errors.password_length_invalid" ))
728+ } else if strings .Contains (err .Error (), "两次输入密码不匹配" ) {
729+ return errors .New (locales .Get ("errors.password_not_match" ))
730+ } else if strings .Contains (err .Error (), "请输入密码" ) {
731+ return errors .New (locales .Get ("errors.password_empty" ))
732+ }
733+ // 默认返回密码无效的错误
734+ return errors .New (locales .Get ("errors.password_empty" ))
735+ }
736+
737+ // 查找重置令牌
738+ emailCode := EmailCodeService .FindOne (sqls .NewCnd ().Eq ("token" , token ))
739+ if emailCode == nil || emailCode .Used {
740+ return errors .New (locales .Get ("errors.reset_link_invalid" ))
741+ }
742+
743+ // 检查令牌是否过期
744+ if dates .FromTimestamp (emailCode .CreateTime ).Add (time .Hour * time .Duration (passwordResetExpireHour )).Before (time .Now ()) {
745+ return errors .New (locales .Get ("errors.reset_link_expired" ))
746+ }
747+
748+ // 更新用户密码
749+ encodedPassword := passwd .EncodePassword (password )
750+ if err := s .UpdateColumn (emailCode .UserId , "password" , encodedPassword ); err != nil {
751+ return err
752+ }
753+
754+ return nil
755+ }
756+
757+ // GetUserByPasswordResetToken 根据密码重置令牌获取用户
758+ func (s * userService ) GetUserByPasswordResetToken (token string ) (* models.User , error ) {
759+ emailCode := EmailCodeService .FindOne (sqls .NewCnd ().Eq ("token" , token ))
760+ if emailCode == nil || emailCode .Used {
761+ return nil , errors .New (locales .Get ("errors.reset_link_invalid" ))
762+ }
763+
764+ user := s .Get (emailCode .UserId )
765+ if user == nil {
766+ return nil , errors .New (locales .Get ("errors.user_not_found" ))
767+ }
768+
769+ return user , nil
770+ }
771+
772+ // MarkPasswordResetTokenUsed 标记密码重置令牌已使用
773+ func (s * userService ) MarkPasswordResetTokenUsed (token string ) error {
774+ emailCode := EmailCodeService .FindOne (sqls .NewCnd ().Eq ("token" , token ))
775+ if emailCode == nil {
776+ return errors .New (locales .Get ("errors.reset_link_invalid" ))
777+ }
778+
779+ return repositories .EmailCodeRepository .UpdateColumn (sqls .DB (), emailCode .Id , "used" , true )
780+ }
0 commit comments