Skip to content

Commit

Permalink
Merge pull request #318 from licon/feature/dingtalk-msg
Browse files Browse the repository at this point in the history
feat: 增加钉钉企业内部应用消息通知功能。
  • Loading branch information
lanyulei authored Nov 18, 2024
2 parents 20246f9 + 930fa91 commit 2a20e73
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 0 deletions.
5 changes: 5 additions & 0 deletions config/settings.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
201 changes: 201 additions & 0 deletions pkg/notify/dingtalk/dingtalk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* @Author: licon [email protected]
* @LastEditors: licon [email protected]
* @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 **标题&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:** " + msgTitle + " " +
"\n **创建人&nbsp;&nbsp;&nbsp;&nbsp;:** " + msgCreator + " " +
"\n **优先级&nbsp;&nbsp;&nbsp;&nbsp;:** " + priority + " " +
"\n **创建时间:** " + createdAt + " " +
"\n **当前时间:** " + nowStr + " " +
"\n [去处理](" + url + ")"

err = SendFlowMsg(token, content)
if err != nil {
logger.Info(err)
}
logger.Info("send dingtalk notify successfully")
return
}
9 changes: 9 additions & 0 deletions pkg/notify/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -57,6 +59,7 @@ func (b *BodyData) ParsingTemplate() (err error) {
func (b *BodyData) SendNotify() (err error) {
var (
emailList []string
phoneList []string
)

switch b.Priority {
Expand All @@ -75,13 +78,19 @@ 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 {
logger.Errorf("模版内容解析失败,%v", 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)
}
}
}
}
Expand Down

0 comments on commit 2a20e73

Please sign in to comment.