206 lines
6.9 KiB
Go
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)
|
|
}
|