Files
likedream/internal/framework/schedule/cpdaily_handler.go
T
2025-11-04 00:32:22 +08:00

206 lines
6.9 KiB
Go

package schedule
import (
"bytes"
"context"
"encoding/gob"
"likedream-goframe/internal/application/cpdaily/login"
"likedream-goframe/internal/application/cpdaily/school"
cpdailyTask "likedream-goframe/internal/application/cpdaily/task"
"likedream-goframe/internal/application/cpdaily/task/formtype"
"likedream-goframe/internal/db"
"likedream-goframe/internal/ent"
"likedream-goframe/internal/ent/cptask"
"likedream-goframe/internal/ent/cpuser"
"likedream-goframe/internal/ent/sysuser"
"likedream-goframe/internal/framework/errors"
"likedream-goframe/internal/framework/model/email"
email2 "likedream-goframe/internal/service/email"
"likedream-goframe/internal/utils"
"time"
"github.com/bytedance/sonic"
"github.com/google/uuid"
"github.com/hibiken/asynq"
"github.com/samber/oops"
)
var emailService = email2.NewV1()
type CpdailyTaskHandler struct{}
func (c *CpdailyTaskHandler) ProcessTask(ctx context.Context, task *asynq.Task) (err error) {
defer utils.Pass(&err)
// 解码payload
var taskPayload CpdailyTaskPayload
e := gob.NewDecoder(bytes.NewReader(task.Payload())).Decode(&taskPayload)
utils.OkOrPanic(e, oops.WithContext(ctx).With("payload", task.Payload(), "type", task.Type()).In("CpdailyTask.DecodePayload").Wrap)
// 查询指定的任务和关联今日校园用户
targetTask, e := db.Global.CpTask.Query().Where(cptask.ID(taskPayload.CpTaskID)).
WithCpUser(func(cuq *ent.CpUserQuery) {
cuq.
WithSysuser(func(suq *ent.SysUserQuery) {
suq.Select(sysuser.FieldID, sysuser.FieldEmail)
})
}).First(ctx)
if ent.IsNotFound(e) {
utils.OkOrPanic(oops.WithContext(ctx).With("task_id", taskPayload.CpTaskID).In("CpdailyTask.ProcessTask").Wrap(e))
}
utils.OkOrPanic(e, oops.WithContext(ctx).With("task_id", taskPayload.CpTaskID).In("CpdailyTask.ProcessTask").Wrap)
db.Global.CpTask.UpdateOneID(taskPayload.CpTaskID).SetTaskStatus(cptask.TaskStatusDoing).ExecX(ctx)
defer utils.HandleError(func(err error) {
e := db.Global.CpTask.UpdateOneID(taskPayload.CpTaskID).SetTaskStatus(cptask.TaskStatusFail).Exec(ctx)
utils.LogError(ctx, "设置任务状态失败", oops.With("task_id", taskPayload.CpTaskID).Wrap(e))
var errorMessage string
if e1, ok := utils.Of[*errors.BusinessError](err); ok {
errorMessage = e1.Message()
} else {
errorMessage = "未知的错误导致任务执行失败"
}
e = db.Global.CpTaskLog.Create().
SetCpTaskID(taskPayload.CpTaskID).
SetCpUserID(targetTask.Edges.CpUser.ID).
SetSystemUserID(targetTask.Edges.CpUser.Edges.Sysuser.ID).
SetIsSuccess(false).
SetRealName("").
SetErrorMessage(errorMessage).
Exec(ctx)
utils.LogError(ctx, "创建任务日志失败", oops.With("task_id", taskPayload.CpTaskID).Wrap(e))
// 发送任务失败通知邮件
c.sendTaskNotificationEmail(ctx, targetTask, email.TaskStatusFailed, map[string]string{
"任务名称": targetTask.Title,
"执行时间": time.Now().Format("2006-01-02 15:04:05"),
"执行结果": "失败",
"错误信息": errorMessage,
})
panic(err)
})
// 查询学校详情
schoolDetail := school.GetSchoolDetail(ctx, targetTask.Edges.CpUser.SchoolID)
// 执行登录
loginExecutor := login.GetCpdailyLoginBySchoolInfo(ctx, &schoolDetail)
loginExecutor.Login(ctx, &schoolDetail, targetTask.Edges.CpUser.Username, targetTask.Edges.CpUser.Password)
restyClient := loginExecutor.GetClient()
// 获取任务执行handler
var taskExecutor cpdailyTask.CpdailyTask
switch targetTask.TaskType {
case cptask.TaskTypeCollection:
taskExecutor = cpdailyTask.NewCollectionTask(restyClient, schoolDetail.WecloudUrl)
case cptask.TaskTypeSign:
taskExecutor = cpdailyTask.NewAutoSignTask(restyClient, schoolDetail.WecloudUrl)
case cptask.TaskTypeSleepCheck:
taskExecutor = cpdailyTask.NewSleepCheckTask(restyClient, schoolDetail.WecloudUrl)
default:
utils.OkOrPanic(oops.WithContext(ctx).With("task_id", taskPayload.CpTaskID).In("CpdailyTask.ProcessTask").Errorf("unknown task type: %s", targetTask.TaskType))
}
cpdailyRealTask := taskExecutor.QueryFormByTitle(ctx, targetTask.Title)
realTitleVar := cpdailyRealTask["realTitle"]
if realTitleVar == nil {
utils.OkOrPanic(errors.NewBusinessErrorWithDetail(503,
"未找到表单数据",
oops.WithContext(ctx).
With("task_id", taskPayload.CpTaskID).
In("CpdailyTask.ProcessTask").
Errorf("real title not found")))
}
realTitle := realTitleVar.String()
var customFormItems []*formtype.CpTaskFormItem
e = sonic.UnmarshalString(targetTask.FormData, &customFormItems)
utils.OkOrPanic(e, oops.WithContext(ctx).With("task_id", taskPayload.CpTaskID).In("CpdailyTask.ProcessTask").Wrap)
var deviceID string
switch targetTask.Edges.CpUser.MobileType {
case cpuser.MobileTypeRandom:
deviceID = uuid.NewString()
case cpuser.MobileTypeAuthorize:
deviceID = targetTask.Edges.CpUser.MobileCode
default:
utils.OkOrPanic(errors.NewBusinessErrorWithDetail(503, "不支持的设备类型", targetTask.Edges.CpUser.MobileType))
}
submitForm := taskExecutor.FillCustomForm(ctx, cpdailyRealTask, customFormItems, deviceID, targetTask.Edges.CpUser.Username)
taskExecutor.Submit(ctx, submitForm, targetTask.Edges.CpUser.Username, deviceID)
db.Global.CpTask.UpdateOneID(taskPayload.CpTaskID).SetTaskStatus(cptask.TaskStatusDone).AddSuccessCount(1).ExecX(ctx)
// 创建日志
db.Global.CpTaskLog.Create().
SetCpTaskID(targetTask.ID).
SetCpUserID(targetTask.Edges.CpUser.ID).
SetSystemUserID(targetTask.Edges.CpUser.Edges.Sysuser.ID).
SetIsSuccess(true).
SetRealName(realTitle).
ExecX(ctx)
// 发送任务成功通知邮件
c.sendTaskNotificationEmail(ctx, targetTask, email.TaskStatusSuccess, map[string]string{
"任务名称": realTitle,
"执行时间": time.Now().Format("2006-01-02 15:04:05"),
"执行结果": "成功",
})
return
}
// sendTaskNotificationEmail 发送任务通知邮件
func (c *CpdailyTaskHandler) sendTaskNotificationEmail(ctx context.Context, task *ent.CpTask, status email.TaskStatus, details map[string]string) {
// 检查是否需要发送邮件通知
if task.NotificationType == cptask.NotificationTypeNone {
return
}
var emailAddr string
var taskName string
switch status {
case email.TaskStatusSuccess:
taskName = "任务[成功]通知"
case email.TaskStatusFailed:
taskName = "任务[失败]通知"
default:
taskName = "任务状态通知"
}
// 根据通知类型确定邮件地址
switch task.NotificationType {
case cptask.NotificationTypeCpUserEmail:
if task.Edges.CpUser != nil && task.Edges.CpUser.Email != "" {
emailAddr = task.Edges.CpUser.Email
}
case cptask.NotificationTypeSystemUserEmail:
if task.Edges.CpUser != nil && task.Edges.CpUser.Edges.Sysuser != nil && task.Edges.CpUser.Edges.Sysuser.Email != "" {
emailAddr = task.Edges.CpUser.Edges.Sysuser.Email
}
}
if emailAddr == "" {
return // 没有邮箱地址,不发送邮件
}
emailService.SendTaskNotificationEmail(ctx, emailAddr, taskName, status, details)
}