// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . //go:build plus package tasks import ( "fmt" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" "github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/senders/mediasenders" "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" "github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/types" "net/mail" "strings" "time" ) func init() { dbs.OnReadyDone(func() { goman.New(func() { NewUserEmailVerificationTask(30 * time.Second).Start() }) }) } // UserEmailVerificationTask 用户邮件验证任务 type UserEmailVerificationTask struct { BaseTask duration time.Duration } func NewUserEmailVerificationTask(duration time.Duration) *UserEmailVerificationTask { return &UserEmailVerificationTask{ duration: duration, } } func (this *UserEmailVerificationTask) Start() { var ticker = time.NewTicker(this.duration) for range ticker.C { err := this.Loop() if err != nil { remotelogs.Error("UserEmailVerificationTask", err.Error()) } } } func (this *UserEmailVerificationTask) Loop() error { if !this.IsPrimaryNode() { return nil } var tx *dbs.Tx // 注册设置 registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx) if err != nil { return err } if !registerConfig.EmailVerification.IsOn { return nil } // 删除过期的认证 var life = registerConfig.EmailVerification.Life if life <= 0 { life = userconfigs.EmailVerificationDefaultLife } var lifeDays = life / 86400 if lifeDays <= 0 { lifeDays = 1 } err = models.SharedUserEmailVerificationDAO.DeleteExpiredVerifications(tx, lifeDays) if err != nil { return err } // 检查邮件设置 senderConfig, err := models.SharedSysSettingDAO.ReadUserSenderConfig(tx) if err != nil { return err } var verifyEmail = senderConfig.VerifyEmail if verifyEmail == nil { // TODO 思考是否需要用户没有设置 return nil } if !verifyEmail.IsOn { return nil } // 查找等待发送的认证 verifications, err := models.SharedUserEmailVerificationDAO.ListSendingVerifications(tx, 10 /** 单次10封 **/) if err != nil { return err } if len(verifications) == 0 { return nil } // 准备邮件中的参数 productName, err := models.SharedSysSettingDAO.ReadProductName(tx) if err != nil { return err } if len(productName) == 0 { productName = teaconst.ProductNameZH } userNodeAddr, err := models.SharedUserNodeDAO.FindUserNodeAccessAddr(tx) if err != nil { return err } var mailInfos = []*mediasenders.MailInfo{} var verificationIds = []int64{} for _, verification := range verifications { // 检查时间 if int64(verification.CreatedAt) < time.Now().Unix()-int64(life) { // 已过期,设置为已发送 err = models.SharedUserEmailVerificationDAO.DeleteVerification(tx, int64(verification.Id)) if err != nil { return err } continue } _, err = mail.ParseAddress(verification.Email) if err != nil { // 邮件已发送,设置为已发送 err = models.SharedUserEmailVerificationDAO.DeleteVerification(tx, int64(verification.Id)) if err != nil { return err } continue } // 标题和内容 var subject = registerConfig.EmailVerification.Subject subject = strings.ReplaceAll(subject, "${product.name}", productName) var body = registerConfig.EmailVerification.Body body = strings.ReplaceAll(body, "${product.name}", productName) body = strings.ReplaceAll(body, "${url.home}", userNodeAddr) body = strings.ReplaceAll(body, "${url.verify}", userNodeAddr+"/email/verify/"+verification.Code) mailInfos = append(mailInfos, &mediasenders.MailInfo{ To: verification.Email, Subject: subject, Body: body, }) if Tea.IsTesting() { logs.Println("sending verification mail to :", verification.Email) } verificationIds = append(verificationIds, int64(verification.Id)) } if len(mailInfos) == 0 { return nil } // 发送 var mailSender = mediasenders.NewEmailMedia() mailSender.Protocol = verifyEmail.Protocol mailSender.SMTP = verifyEmail.SMTPHost + ":" + types.String(verifyEmail.SMTPPort) mailSender.Username = verifyEmail.Username mailSender.Password = verifyEmail.Password mailSender.From = verifyEmail.FromEmail mailSender.FromName = verifyEmail.FromName err = mailSender.SendMails(mailInfos, productName) if err != nil { return fmt.Errorf("send mail failed: %w", err) } // 设置为已发送 for _, verificationId := range verificationIds { err = models.SharedUserEmailVerificationDAO.UpdateVerificationIsSent(tx, verificationId) if err != nil { return err } } return nil }