mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 05:56:38 +08:00
130 lines
3.6 KiB
Go
130 lines
3.6 KiB
Go
/*
|
|
Copyright 2026 linux.do
|
|
Modified by Arctel.net, 2026
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package user
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/Rain-kl/Wavelet/internal/model"
|
|
"github.com/Rain-kl/Wavelet/internal/task"
|
|
"github.com/Rain-kl/Wavelet/internal/util/mail"
|
|
)
|
|
|
|
// SendEmailPayload 邮件发送任务载荷
|
|
type SendEmailPayload struct {
|
|
To string `json:"to"`
|
|
Subject string `json:"subject"`
|
|
Body string `json:"body"`
|
|
}
|
|
|
|
// SendEmailHandler 发送验证码邮件的异步任务处理器
|
|
type SendEmailHandler struct{}
|
|
|
|
// ValidatePayload 实现 task.PayloadValidator 接口
|
|
// 校验并标准化邮件发送参数,框架在 Admin 下发时自动调用
|
|
func (h *SendEmailHandler) ValidatePayload(payload []byte) ([]byte, error) {
|
|
if len(payload) == 0 {
|
|
return nil, errors.New("任务参数不能为空")
|
|
}
|
|
|
|
var req SendEmailPayload
|
|
if err := json.Unmarshal(payload, &req); err != nil {
|
|
return nil, fmt.Errorf("无效的 JSON 格式: %w", err)
|
|
}
|
|
|
|
req.To = strings.TrimSpace(req.To)
|
|
req.Subject = strings.TrimSpace(req.Subject)
|
|
req.Body = strings.TrimSpace(req.Body)
|
|
|
|
if req.To == "" || req.Subject == "" || req.Body == "" {
|
|
return nil, errors.New("to、subject、body 不能为空")
|
|
}
|
|
|
|
return json.Marshal(req)
|
|
}
|
|
|
|
// Execute 执行邮件异步发送逻辑
|
|
func (h *SendEmailHandler) Execute(ctx context.Context, payload []byte) (*task.TaskResult, error) {
|
|
var req SendEmailPayload
|
|
if err := json.Unmarshal(payload, &req); err != nil {
|
|
task.AppendLog(ctx, "解析邮件发送参数失败: %v", err)
|
|
return nil, fmt.Errorf("解析邮件发送参数失败: %w", err)
|
|
}
|
|
|
|
task.AppendLog(ctx, "开始准备发送邮件到: %s, 主题: %s", req.To, req.Subject)
|
|
|
|
// 从数据库读取最新的 SMTP 系统配置
|
|
var smtpHost string
|
|
var smtpPortVal string
|
|
var smtpUsername string
|
|
var smtpPassword string
|
|
|
|
var sc model.SystemConfig
|
|
if err := sc.GetByKey(ctx, model.ConfigKeySMTPHost); err == nil {
|
|
smtpHost = sc.Value
|
|
}
|
|
if err := sc.GetByKey(ctx, model.ConfigKeySMTPPort); err == nil {
|
|
smtpPortVal = sc.Value
|
|
}
|
|
if err := sc.GetByKey(ctx, model.ConfigKeySMTPUsername); err == nil {
|
|
smtpUsername = sc.Value
|
|
}
|
|
if err := sc.GetByKey(ctx, model.ConfigKeySMTPPassword); err == nil {
|
|
smtpPassword = sc.Value
|
|
}
|
|
|
|
if smtpHost == "" || smtpPortVal == "" || smtpUsername == "" {
|
|
err := errors.New("系统 SMTP 邮件服务配置不完整")
|
|
task.AppendLog(ctx, "发送失败: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
smtpPort, err := strconv.Atoi(smtpPortVal)
|
|
if err != nil {
|
|
smtpPort = 587
|
|
}
|
|
|
|
cfg := mail.Config{
|
|
Host: smtpHost,
|
|
Port: smtpPort,
|
|
Username: smtpUsername,
|
|
Password: smtpPassword,
|
|
}
|
|
|
|
task.AppendLog(ctx, "连接 SMTP 服务器: %s:%d, 用户名: %s", smtpHost, smtpPort, smtpUsername)
|
|
|
|
// 调用 SendMailHTML 执行邮件发送,这里会有 5s 拨号超时和 10s 读写限制
|
|
err = mail.SendMailHTML(cfg, req.To, req.Subject, req.Body)
|
|
if err != nil {
|
|
task.AppendLog(ctx, "邮件发送失败: %v", err)
|
|
return nil, fmt.Errorf("发送邮件失败: %w", err)
|
|
}
|
|
|
|
msg := fmt.Sprintf("邮件成功发送至: %s", req.To)
|
|
task.AppendLog(ctx, "%s", msg)
|
|
|
|
return &task.TaskResult{
|
|
Message: msg,
|
|
}, nil
|
|
}
|