Merge pull request #318 from licon/feature/dingtalk-msg
feat: 增加钉钉企业内部应用消息通知功能。
This commit is contained in:
@@ -17,6 +17,11 @@ settings:
|
||||
password: 123456
|
||||
port: 3306
|
||||
username: root
|
||||
dingtalk:
|
||||
agentid: 1234567890
|
||||
appkey: your dingtalk appkey
|
||||
appsecret: your dingtalk appsecret
|
||||
enable: false
|
||||
domain:
|
||||
gethost: 1
|
||||
url: localhost:9527
|
||||
|
||||
@@ -17,6 +17,11 @@ settings:
|
||||
password: 123456
|
||||
port: 3306
|
||||
username: root
|
||||
dingtalk:
|
||||
agentid: 1234567890
|
||||
appkey: your dingtalk appkey
|
||||
appsecret: your dingtalk appsecret
|
||||
enable: false
|
||||
domain:
|
||||
gethost: 1
|
||||
url: localhost:9527
|
||||
|
||||
201
pkg/notify/dingtalk/dingtalk.go
Normal file
201
pkg/notify/dingtalk/dingtalk.go
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* @Author: licon licon.ye@gmail.com
|
||||
* @LastEditors: licon licon.ye@gmail.com
|
||||
* @FilePath: /pkg/notify/dingtalk/dingtalk.go
|
||||
* @Description: 发送钉钉第三方应用消息, 需要工单系统内的用户手机号与钉钉上一致
|
||||
*/
|
||||
package dingtalk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"ferry/pkg/logger"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// var appKey = viper.GetString("settings.dingtalk.appkey")
|
||||
// var appSecret = viper.GetString("settings.dingtalk.appsecret")
|
||||
// var agentId = viper.GetInt64("settings.dingtalk.agentid")
|
||||
|
||||
const (
|
||||
GetAccessTokenUrl = "https://oapi.dingtalk.com/gettoken"
|
||||
SendWorkMsgUrl = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"
|
||||
GetUserInfoByMobileUrl = "https://oapi.dingtalk.com/topapi/v2/user/getbymobile"
|
||||
)
|
||||
|
||||
type UserDetailInfo struct {
|
||||
LoginName string `gorm:"login_name" json:"login_name"`
|
||||
UserId string `gorm:"user_id" json:"user_id"`
|
||||
}
|
||||
type TokenResp struct {
|
||||
Errcode int64 `json:"errcode"`
|
||||
AccessToken string `json:"access_token"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
ExpiresIn int64 `json:"expires_in"`
|
||||
}
|
||||
|
||||
type MsgBody struct {
|
||||
Msgtype string `json:"msgtype"`
|
||||
Markdown struct {
|
||||
Title string `json:"title"`
|
||||
Text string `json:"text"`
|
||||
} `json:"markdown"`
|
||||
}
|
||||
type SendFlowMsgBody struct {
|
||||
AgentId int64 `json:"agent_id"`
|
||||
UseridList string `json:"userid_list"`
|
||||
Msg MsgBody `json:"msg"`
|
||||
}
|
||||
|
||||
type SendFlowResp struct {
|
||||
Errcode int64 `json:"errcode"`
|
||||
TaskId int64 `json:"task_id"`
|
||||
RequestId string `json:"request_id"`
|
||||
}
|
||||
|
||||
type GetUserByMobileReq struct {
|
||||
Mobile string `json:"mobile"`
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Userid string `json:"userid"`
|
||||
}
|
||||
|
||||
type GetUserByMobileResp struct {
|
||||
Errcode int64 `json:"errcode"`
|
||||
RequestId string `json:"request_id"`
|
||||
Result *Result `json:"result"`
|
||||
}
|
||||
|
||||
func GetDingUidByMobile(token string, req GetUserByMobileReq) string {
|
||||
b, _ := json.Marshal(req)
|
||||
resp, err := http.Post(fmt.Sprintf("%s?access_token=%s", GetUserInfoByMobileUrl, token), "application/json", bytes.NewBuffer(b))
|
||||
if err != nil {
|
||||
logger.Info(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
var jsonBody GetUserByMobileResp
|
||||
json.Unmarshal(body, &jsonBody)
|
||||
if jsonBody.Errcode != 0 {
|
||||
logger.Info("GetDingUidByMobile error")
|
||||
return ""
|
||||
}
|
||||
if jsonBody.Result != nil {
|
||||
return jsonBody.Result.Userid
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func GetAccessToken(appKey, appSecret string) string {
|
||||
res, err := http.Get(fmt.Sprintf("%s?appkey=%s&appsecret=%s", GetAccessTokenUrl, appKey, appSecret))
|
||||
if err != nil {
|
||||
logger.Info(err)
|
||||
return ""
|
||||
}
|
||||
defer res.Body.Close()
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
logger.Info(err)
|
||||
return ""
|
||||
}
|
||||
var token TokenResp
|
||||
json.Unmarshal(body, &token)
|
||||
if err != nil {
|
||||
logger.Info(err)
|
||||
return ""
|
||||
}
|
||||
if token.Errcode == 0 {
|
||||
return token.AccessToken
|
||||
} else {
|
||||
logger.Info(token.Errmsg)
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func SendFlowMsg(token string, content SendFlowMsgBody) error {
|
||||
b, _ := json.Marshal(content)
|
||||
resp, err := http.Post(fmt.Sprintf("%s?access_token=%s", SendWorkMsgUrl, token), "application/json", bytes.NewBuffer(b))
|
||||
if err != nil {
|
||||
logger.Info(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
var jsonBody SendFlowResp
|
||||
json.Unmarshal(body, &jsonBody)
|
||||
if jsonBody.Errcode != 0 {
|
||||
logger.Info(err)
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func SendDingMsg(phoneList []string, url string, msgTitle string, msgCreator string, priority string, createdAt string) {
|
||||
appKey := viper.GetString("settings.dingtalk.appkey")
|
||||
appSecret := viper.GetString("settings.dingtalk.appsecret")
|
||||
agentId := viper.GetInt64("settings.dingtalk.agentid")
|
||||
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: viper.GetString("settings.redis.host"),
|
||||
Password: viper.GetString("settings.redis.pwd"),
|
||||
DB: 1, // use default DB
|
||||
})
|
||||
|
||||
var token string
|
||||
tokenByte, err := client.Get("accessTokenDingtalk").Result()
|
||||
|
||||
if err != nil {
|
||||
logger.Info(err)
|
||||
token = GetAccessToken(appKey, appSecret)
|
||||
err = client.Set("accessTokenDingtalk", token, 120*time.Minute).Err()
|
||||
if err != nil {
|
||||
logger.Info(err)
|
||||
}
|
||||
} else {
|
||||
token = string(tokenByte)
|
||||
}
|
||||
var userId string
|
||||
|
||||
var uids []string
|
||||
var getDingUidByMobileReq GetUserByMobileReq
|
||||
for i := 0; i < len(phoneList); i++ {
|
||||
getDingUidByMobileReq.Mobile = phoneList[i]
|
||||
userId = GetDingUidByMobile(token, getDingUidByMobileReq)
|
||||
if userId != "" {
|
||||
uids = append(uids, userId)
|
||||
}
|
||||
}
|
||||
if len(uids) == 0 {
|
||||
return
|
||||
}
|
||||
uidsString := strings.Join(uids, ",")
|
||||
nowStr := time.Now().Format("2006-01-02 15:04:05")
|
||||
var content SendFlowMsgBody
|
||||
content.AgentId = agentId
|
||||
content.UseridList = uidsString
|
||||
content.Msg.Msgtype = "markdown"
|
||||
content.Msg.Markdown.Title = "新工单提醒"
|
||||
content.Msg.Markdown.Text = "# 你有一个待办工单需要处理: " +
|
||||
"\n **标题 :** " + msgTitle + " " +
|
||||
"\n **创建人 :** " + msgCreator + " " +
|
||||
"\n **优先级 :** " + priority + " " +
|
||||
"\n **创建时间:** " + createdAt + " " +
|
||||
"\n **当前时间:** " + nowStr + " " +
|
||||
"\n [去处理](" + url + ")"
|
||||
|
||||
err = SendFlowMsg(token, content)
|
||||
if err != nil {
|
||||
logger.Info(err)
|
||||
}
|
||||
logger.Info("send dingtalk notify successfully")
|
||||
return
|
||||
}
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"bytes"
|
||||
"ferry/models/system"
|
||||
"ferry/pkg/logger"
|
||||
"ferry/pkg/notify/dingtalk"
|
||||
"ferry/pkg/notify/email"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
@@ -57,6 +59,7 @@ func (b *BodyData) ParsingTemplate() (err error) {
|
||||
func (b *BodyData) SendNotify() (err error) {
|
||||
var (
|
||||
emailList []string
|
||||
phoneList []string
|
||||
)
|
||||
|
||||
switch b.Priority {
|
||||
@@ -75,6 +78,7 @@ func (b *BodyData) SendNotify() (err error) {
|
||||
if len(users) > 0 {
|
||||
for _, user := range users {
|
||||
emailList = append(emailList, user.Email)
|
||||
phoneList = append(phoneList, user.Phone)
|
||||
}
|
||||
err = b.ParsingTemplate()
|
||||
if err != nil {
|
||||
@@ -82,6 +86,11 @@ func (b *BodyData) SendNotify() (err error) {
|
||||
return
|
||||
}
|
||||
go email.SendMail(emailList, b.EmailCcTo, b.Subject, b.Content)
|
||||
dingtalkEnable := viper.GetBool("settings.dingtalk.enable")
|
||||
if dingtalkEnable {
|
||||
url := fmt.Sprintf("%s/#/process/handle-ticket?workOrderId=%d&processId=%d", b.Domain, b.Id, b.ProcessId)
|
||||
go dingtalk.SendDingMsg(phoneList, url, b.Title, b.Creator, b.PriorityValue, b.CreatedAt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user