完成钉钉机器人消息通知

This commit is contained in:
marvzhang
2020-01-15 13:03:43 +08:00
parent 9e61e4c149
commit 32bfb63d8f
5 changed files with 124 additions and 101 deletions

View File

@@ -24,9 +24,8 @@ type User struct {
}
type UserSetting struct {
NotificationTrigger string `json:"notification_trigger" bson:"notification_trigger"`
DingTalkAppKey string `json:"ding_talk_app_key" bson:"ding_talk_app_key"`
DingTalkAppSecret string `json:"ding_talk_app_secret" bson:"ding_talk_app_secret"`
NotificationTrigger string `json:"notification_trigger" bson:"notification_trigger"`
DingTalkRobotWebhook string `json:"ding_talk_robot_webhook" bson:"ding_talk_robot_webhook"`
}
func (user *User) Save() error {

View File

@@ -213,11 +213,10 @@ func GetMe(c *gin.Context) {
func PostMe(c *gin.Context) {
type ReqBody struct {
Email string `json:"email"`
Password string `json:"password"`
NotificationTrigger string `json:"notification_trigger"`
DingTalkAppKey string `json:"ding_talk_app_key"`
DingTalkAppSecret string `json:"ding_talk_app_secret"`
Email string `json:"email"`
Password string `json:"password"`
NotificationTrigger string `json:"notification_trigger"`
DingTalkRobotWebhook string `json:"ding_talk_robot_webhook"`
}
ctx := context.WithGinContext(c)
user := ctx.User()
@@ -239,11 +238,8 @@ func PostMe(c *gin.Context) {
if reqBody.NotificationTrigger != "" {
user.Setting.NotificationTrigger = reqBody.NotificationTrigger
}
if reqBody.DingTalkAppKey != "" {
user.Setting.DingTalkAppKey = reqBody.DingTalkAppKey
}
if reqBody.DingTalkAppSecret != "" {
user.Setting.DingTalkAppSecret = reqBody.DingTalkAppSecret
if reqBody.DingTalkRobotWebhook != "" {
user.Setting.DingTalkRobotWebhook = reqBody.DingTalkRobotWebhook
}
if err := user.Save(); err != nil {
HandleError(http.StatusInternalServerError, c, err)

View File

@@ -1,95 +1,58 @@
package notification
import (
"crawlab/model"
"errors"
"fmt"
"github.com/apex/log"
"github.com/imroc/req"
"github.com/royeo/dingrobot"
"runtime/debug"
)
func SendDingTalkNotification(t model.Task, s model.Spider) error {
// 获取用户
user, _ := model.GetUser(t.UserId)
// 如果AppKey或AppSecret未设置则返回错误
if user.Setting.DingTalkAppKey == "" || user.Setting.DingTalkAppSecret == "" {
return errors.New("ding_talk_app_key or ding_talk_app_secret is empty")
}
// 获取access_token
accessToken, err := GetDingTalkAccessToken(user)
if err != nil {
return err
}
// 时间戳
//timestamp := time.Now().Unix()
// 计算sign
//signRawString := fmt.Sprintf("%d\n%s", timestamp, user.Setting.DingTalkAppSecret)
//sign := utils.ComputeHmacSha256(signRawString, user.Setting.DingTalkAppSecret)
// 请求数据
url := fmt.Sprintf("https://oapi.dingtalk.com/robot/send?access_token=%s", accessToken)
robot := dingrobot.NewRobot(url)
text := "it works"
if err := robot.SendText(text, []string{}, false); err != nil {
log.Errorf(err.Error())
debug.PrintStack()
return err
}
//header := req.Header{
// "Content-Type": "application/json; charset=utf-8",
// "timestamp": fmt.Sprintf("%d000", timestamp),
// "sign": sign,
//}
//data := req.Param{
// "msgtype": "text",
// "text": req.Param{
// "text": "it works",
// },
// "at": req.Param{
// "atMobiles": []string{},
// "isAtAll": false,
// },
//}
//res, err := req.Post(url, header, req.BodyJSON(&data))
//if err != nil {
// log.Errorf("dingtalk notification error: " + err.Error())
// debug.PrintStack()
// return err
//}
//log.Infof(fmt.Sprintf("%+v", res))
return nil
}
func GetDingTalkAccessToken(u model.User) (string, error) {
func SendDingTalkNotification(webhook string, title string, content string) error {
type ResBody struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
AccessToken string `json:"access_token"`
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
// 请求头
header := req.Header{
"Content-Type": "application/json; charset=utf-8",
}
// 请求数据
url := fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", u.Setting.DingTalkAppKey, u.Setting.DingTalkAppSecret)
res, err := req.Get(url)
if err != nil {
log.Errorf("get dingtalk access_token error: " + err.Error())
debug.PrintStack()
return "", err
data := req.Param{
"msgtype": "markdown",
"markdown": req.Param{
"title": title,
"text": content,
},
"at": req.Param{
"atMobiles": []string{},
"isAtAll": false,
},
}
// 解析相应body
// 发起请求
res, err := req.Post(webhook, header, req.BodyJSON(&data))
if err != nil {
log.Errorf("dingtalk notification error: " + err.Error())
debug.PrintStack()
return err
}
// 解析响应
var resBody ResBody
if err := res.ToJSON(&resBody); err != nil {
log.Errorf("get dingtalk access_token error: " + err.Error())
log.Errorf("dingtalk notification error: " + err.Error())
debug.PrintStack()
return "", err
return err
}
return resBody.AccessToken, nil
// 判断响应是否报错
if resBody.ErrCode != 0 {
log.Errorf("dingtalk notification error: " + resBody.ErrMsg)
debug.PrintStack()
return errors.New(resBody.ErrMsg)
}
return nil
}

View File

@@ -489,9 +489,14 @@ func ExecuteTask(id int) {
// 如果发生错误,则发送通知
t, _ = model.GetTask(t.Id)
if user.Email != "" &&
(user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskEnd || user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskError) {
SendTaskEmail(user, t, spider)
if user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskEnd || user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskError {
if user.Email != "" {
SendTaskEmail(user, t, spider)
}
if user.Setting.DingTalkRobotWebhook != "" {
SendTaskDingTalk(user, t, spider)
}
}
return
}
@@ -516,12 +521,13 @@ func ExecuteTask(id int) {
t.TotalDuration = t.FinishTs.Sub(t.CreateTs).Seconds() // 总时长
// 如果是任务结束时发送通知,则发送通知
if user.Email != "" &&
user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskEnd {
SendTaskEmail(user, t, spider)
if err := notification.SendDingTalkNotification(t, spider); err != nil {
log.Errorf(err.Error())
debug.PrintStack()
if user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskEnd {
if user.Email != "" {
SendTaskEmail(user, t, spider)
}
if user.Setting.DingTalkRobotWebhook != "" {
SendTaskDingTalk(user, t, spider)
}
}
@@ -695,7 +701,7 @@ func HandleTaskError(t model.Task, err error) {
debug.PrintStack()
}
func GetTaskEmailContent(t model.Task, s model.Spider) string {
func GetTaskEmailMarkdownContent(t model.Task, s model.Spider) string {
n, _ := model.GetNode(t.NodeId)
errMsg := ""
statusMsg := fmt.Sprintf(`<span style="color:green">%s</span>`, t.Status)
@@ -743,22 +749,82 @@ Please login to Crawlab to view the details.
)
}
func GetTaskDingTalkMarkdownContent(t model.Task, s model.Spider) string {
n, _ := model.GetNode(t.NodeId)
errMsg := ""
statusMsg := fmt.Sprintf(`<font color=green>%s</font>`, t.Status)
if t.Status == constants.StatusError {
errMsg = `<font color="red">(有错误)</font>`
statusMsg = fmt.Sprintf(`<font color=red>%s</font>`, t.Status)
}
return fmt.Sprintf(`
您的任务已完成%s请查看任务信息如下。
> **任务ID:** %s
> **任务状态:** %s
> **任务参数:** %s
> **爬虫ID:** %s
> **爬虫名称:** %s
> **节点:** %s
> **创建时间:** %s
> **开始时间:** %s
> **完成时间:** %s
> **等待时间:** %.0f秒
> **运行时间:** %.0f秒
> **总时间:** %.0f秒
> **结果数:** %d
> **错误:** %s
请登录Crawlab查看详情。
`,
errMsg,
t.Id,
statusMsg,
t.Param,
s.Id.Hex(),
s.Name,
n.Name,
utils.GetLocalTimeString(t.CreateTs),
utils.GetLocalTimeString(t.StartTs),
utils.GetLocalTimeString(t.FinishTs),
t.WaitDuration,
t.RuntimeDuration,
t.TotalDuration,
t.ResultCount,
t.Error,
)
}
func SendTaskEmail(u model.User, t model.Task, s model.Spider) {
statusMsg := "has finished"
if t.Status == constants.StatusError {
statusMsg = "has an error"
}
title := fmt.Sprintf("[Crawlab] Task for \"%s\" %s", s.Name, statusMsg)
if err := notification.SendMail(
u.Email,
u.Username,
fmt.Sprintf("[Crawlab] Task for \"%s\" %s", s.Name, statusMsg),
GetTaskEmailContent(t, s),
title,
GetTaskEmailMarkdownContent(t, s),
); err != nil {
log.Errorf("mail error: " + err.Error())
debug.PrintStack()
}
}
func SendTaskDingTalk(u model.User, t model.Task, s model.Spider) {
statusMsg := "has finished"
if t.Status == constants.StatusError {
statusMsg = "has an error"
}
title := fmt.Sprintf("[Crawlab] Task for \"%s\" %s", s.Name, statusMsg)
content := GetTaskDingTalkMarkdownContent(t, s)
if err := notification.SendDingTalkNotification(u.Setting.DingTalkRobotWebhook, title, content); err != nil {
log.Errorf(err.Error())
debug.PrintStack()
}
}
func InitTaskExecutor() error {
c := cron.New(cron.WithSeconds())
Exec = &Executor{

View File

@@ -353,8 +353,7 @@ export default {
'On Task End': '当任务结束',
'On Task Error': '当任务发生错误',
'Never': '从不',
'DingTalk AppKey': '钉钉 AppKey',
'DingTalk AppSecret': '钉钉 AppSecret',
'DingTalk Robot Webhook': '钉钉机器人 Webhook',
// 其他
tagsView: {