2017-07-04 08:16:32 -05:00
package notifiers
import (
2018-10-25 05:17:05 -05:00
"fmt"
2018-11-08 04:44:00 -06:00
"net/url"
2018-10-25 05:17:05 -05:00
2017-07-04 08:16:32 -05:00
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
2018-10-25 05:29:47 -05:00
const DefaultDingdingMsgType = "link"
2018-10-25 05:24:04 -05:00
const DingdingOptionsTemplate = `
2017-07-04 08:16:32 -05:00
< h3 class = "page-heading" > DingDing settings < / h3 >
< div class = "gf-form" >
< span class = "gf-form-label width-10" > Url < / span >
2018-11-08 04:44:00 -06:00
< input type = "text" required class = "gf-form-input max-width-70" ng - model = "ctrl.model.settings.url" placeholder = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxx" > < / input >
2017-07-04 08:16:32 -05:00
< / div >
2018-10-25 05:29:47 -05:00
< div class = "gf-form" >
< span class = "gf-form-label width-10" > MessageType < / span >
< select class = "gf-form-input max-width-14" ng - model = "ctrl.model.settings.msgType" ng - options = "s for s in ['link','actionCard']" ng - init = "ctrl.model.settings.msgType=ctrl.model.settings.msgType || '` + DefaultDingdingMsgType + `'" > < / select >
< / div >
2018-11-08 04:44:00 -06:00
< div class = "gf-form" >
< span class = "gf-form-label width-10" > OpenInBrowser < / span >
< gf - form - switch class = "gf-form" checked = "ctrl.model.settings.openInBrowser" > < / gf - form - switch >
< info - popover mode = "right-normal" > Open the message url in browser instead of inside of Dingding < / info - popover >
< / div >
2018-10-25 05:24:04 -05:00
`
func init ( ) {
alerting . RegisterNotifier ( & alerting . NotifierPlugin {
Type : "dingding" ,
Name : "DingDing" ,
Description : "Sends HTTP POST request to DingDing" ,
Factory : NewDingDingNotifier ,
OptionsTemplate : DingdingOptionsTemplate ,
2017-07-04 08:16:32 -05:00
} )
}
func NewDingDingNotifier ( model * m . AlertNotification ) ( alerting . Notifier , error ) {
url := model . Settings . Get ( "url" ) . MustString ( )
if url == "" {
return nil , alerting . ValidationError { Reason : "Could not find url property in settings" }
}
2018-10-25 05:29:47 -05:00
msgType := model . Settings . Get ( "msgType" ) . MustString ( DefaultDingdingMsgType )
2018-11-08 04:44:00 -06:00
openInBrowser := model . Settings . Get ( "openInBrowser" ) . MustBool ( true )
2018-10-25 05:29:47 -05:00
2017-07-04 08:16:32 -05:00
return & DingDingNotifier {
2018-11-08 04:44:00 -06:00
NotifierBase : NewNotifierBase ( model ) ,
OpenInBrowser : openInBrowser ,
MsgType : msgType ,
Url : url ,
log : log . New ( "alerting.notifier.dingding" ) ,
2017-07-04 08:16:32 -05:00
} , nil
}
type DingDingNotifier struct {
NotifierBase
2018-11-08 04:44:00 -06:00
MsgType string
OpenInBrowser bool //Set whether the message url will open outside of Dingding
Url string
log log . Logger
2017-07-04 08:16:32 -05:00
}
func ( this * DingDingNotifier ) Notify ( evalContext * alerting . EvalContext ) error {
this . log . Info ( "Sending dingding" )
messageUrl , err := evalContext . GetRuleUrl ( )
if err != nil {
this . log . Error ( "Failed to get messageUrl" , "error" , err , "dingding" , this . Name )
messageUrl = ""
}
2018-11-08 04:44:00 -06:00
if this . OpenInBrowser {
q := url . Values {
"pc_slide" : { "false" } ,
"url" : { messageUrl } ,
}
// Use special link to auto open the message url outside of Dingding
// Refer: https://open-doc.dingtalk.com/docs/doc.htm?treeId=385&articleId=104972&docType=1#s9
messageUrl = "dingtalk://dingtalkclient/page/link?" + q . Encode ( )
}
2017-07-04 08:16:32 -05:00
this . log . Info ( "messageUrl:" + messageUrl )
message := evalContext . Rule . Message
picUrl := evalContext . ImagePublicUrl
title := evalContext . GetNotificationTitle ( )
2018-10-19 04:17:38 -05:00
if message == "" {
message = title
}
2017-07-04 08:16:32 -05:00
2018-10-25 05:17:05 -05:00
for i , match := range evalContext . EvalMatches {
2018-10-25 05:53:45 -05:00
message += fmt . Sprintf ( "\\n%2d. %s: %s" , i + 1 , match . Metric , match . Value )
2018-10-25 05:17:05 -05:00
}
2018-10-25 05:29:47 -05:00
var bodyStr string
if this . MsgType == "actionCard" {
2018-11-11 21:18:53 -06:00
// Embed the pic into the markdown directly because actionCard doesn't have a picUrl field
if picUrl != "" {
message = "![](" + picUrl + ")\\n\\n" + message
}
2018-10-25 05:29:47 -05:00
bodyStr = ` {
"msgtype" : "actionCard" ,
"actionCard" : {
"text" : "` + message + `" ,
"title" : "` + title + `" ,
"singleTitle" : "More" ,
"singleURL" : "` + messageUrl + `"
}
} `
} else {
bodyStr = ` {
"msgtype" : "link" ,
"link" : {
"text" : "` + message + `" ,
"title" : "` + title + `" ,
"picUrl" : "` + picUrl + `" ,
"messageUrl" : "` + messageUrl + `"
}
} `
}
2018-10-25 05:24:04 -05:00
bodyJSON , err := simplejson . NewJson ( [ ] byte ( bodyStr ) )
2017-07-04 08:16:32 -05:00
if err != nil {
this . log . Error ( "Failed to create Json data" , "error" , err , "dingding" , this . Name )
}
2018-04-10 15:22:12 -05:00
body , err := bodyJSON . MarshalJSON ( )
if err != nil {
return err
}
2017-07-04 08:16:32 -05:00
cmd := & m . SendWebhookSync {
Url : this . Url ,
Body : string ( body ) ,
}
if err := bus . DispatchCtx ( evalContext . Ctx , cmd ) ; err != nil {
this . log . Error ( "Failed to send DingDing" , "error" , err , "dingding" , this . Name )
return err
}
return nil
}