parent
ad86421cb8
commit
dbcb0ee85b
@ -0,0 +1,50 @@
|
|||||||
|
package dingtalk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gopkg.in/dtapps/go-library.v3/utils/gohttp"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
Secret string
|
||||||
|
AccessToken string
|
||||||
|
ZapLog *zap.Logger // 日志服务
|
||||||
|
Db *gorm.DB // 关系数据库服务
|
||||||
|
RDb *redis.Client // 缓存数据库服务
|
||||||
|
MDb *mongo.Client // 非关系数据库服务
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *App) request(url string, params map[string]interface{}, method string) ([]byte, error) {
|
||||||
|
switch method {
|
||||||
|
case http.MethodGet:
|
||||||
|
// 请求
|
||||||
|
get, err := gohttp.Get(url, params)
|
||||||
|
// 日志
|
||||||
|
if app.ZapLog != nil {
|
||||||
|
app.ZapLog.Sugar().Info(fmt.Sprintf("%s %s", url, get.Body))
|
||||||
|
}
|
||||||
|
return get.Body, err
|
||||||
|
case http.MethodPost:
|
||||||
|
// 请求参数
|
||||||
|
paramsMarshal, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 请求
|
||||||
|
postJson, err := gohttp.PostJson(url, paramsMarshal)
|
||||||
|
// 日志
|
||||||
|
if app.ZapLog != nil {
|
||||||
|
app.ZapLog.Sugar().Info(fmt.Sprintf("%s %s", url, postJson.Body))
|
||||||
|
}
|
||||||
|
return postJson.Body, err
|
||||||
|
default:
|
||||||
|
return nil, errors.New("请求类型不支持")
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
const Api = "https://oapi.dingtalk.com/robot/send"
|
|
@ -1,57 +0,0 @@
|
|||||||
package dingtalk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"gopkg.in/dtapps/go-library.v3/service/dingtalk/config"
|
|
||||||
"gopkg.in/dtapps/go-library.v3/service/dingtalk/message"
|
|
||||||
"gopkg.in/dtapps/go-library.v3/utils/gojson"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DingBot struct {
|
|
||||||
Secret string
|
|
||||||
AccessToken string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Response struct {
|
|
||||||
Errcode int64 `json:"errcode"`
|
|
||||||
Errmsg string `json:"errmsg"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bot *DingBot) Send(msg message.Message) (Response, error) {
|
|
||||||
timestamp := time.Now().UnixNano() / 1e6
|
|
||||||
var response Response
|
|
||||||
signStr := sign(timestamp, bot.Secret)
|
|
||||||
dingUrl := fmt.Sprintf("%s?access_token=%s×tamp=%d&sign=%s", config.Api, bot.AccessToken, timestamp, signStr)
|
|
||||||
toString, err := gojson.MarshalToString(msg)
|
|
||||||
if err != nil {
|
|
||||||
return response, err
|
|
||||||
}
|
|
||||||
resp, e := http.Post(dingUrl, "application/json", strings.NewReader(toString))
|
|
||||||
if e != nil {
|
|
||||||
return response, e
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
|
||||||
e = json.Unmarshal(body, &response)
|
|
||||||
if e != nil {
|
|
||||||
return response, e
|
|
||||||
}
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sign(t int64, secret string) string {
|
|
||||||
secStr := fmt.Sprintf("%d\n%s", t, secret)
|
|
||||||
hmac256 := hmac.New(sha256.New, []byte(secret))
|
|
||||||
hmac256.Write([]byte(secStr))
|
|
||||||
result := hmac256.Sum(nil)
|
|
||||||
return base64.StdEncoding.EncodeToString(result)
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
package message
|
|
||||||
|
|
||||||
type Message struct {
|
|
||||||
MsgType MsgType_ `json:"msgtype"`
|
|
||||||
Text Text_ `json:"text"`
|
|
||||||
Link Link_ `json:"link"`
|
|
||||||
Markdown Markdown_ `json:"markdown"`
|
|
||||||
ActionCard ActionCard_ `json:"actionCard"`
|
|
||||||
FeedCard FeedCard_ `json:"feedCard"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text_ text类型
|
|
||||||
type Text_ struct {
|
|
||||||
Content string `json:"content"`
|
|
||||||
At At_ `json:"at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// At_ At类型
|
|
||||||
type At_ struct {
|
|
||||||
AtMobiles []string `json:"atMobiles"`
|
|
||||||
IsAtAll bool `json:"isAtAll"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link_ link类型
|
|
||||||
type Link_ struct {
|
|
||||||
Text string `json:"text"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
PicUrl string `json:"picUrl"`
|
|
||||||
MessageUrl string `json:"messageUrl"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Markdown_ markdown类型
|
|
||||||
type Markdown_ struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
Text string `json:"text"`
|
|
||||||
At At_ `json:"at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ActionCard_ 整体跳转actionCard
|
|
||||||
type ActionCard_ struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
Text string `json:"text"`
|
|
||||||
BtnOrientation string `json:"btnOrientation"`
|
|
||||||
SingleTitle string `json:"singleTitle"`
|
|
||||||
SingleURL string `json:"singleUrl"`
|
|
||||||
HideAvatar string `json:"hideAvatar"`
|
|
||||||
BtnS []Btn_ `json:"btns"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Btn_ Btn类型
|
|
||||||
type Btn_ struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
ActionURL string `json:"actionURL"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// FeedCard_ FeedCard类型
|
|
||||||
type FeedCard_ struct {
|
|
||||||
Links []Link_ `json:"links"`
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package message
|
|
||||||
|
|
||||||
type MsgType_ string
|
|
||||||
|
|
||||||
const (
|
|
||||||
TextStr MsgType_ = "text"
|
|
||||||
LinkStr MsgType_ = "link"
|
|
||||||
MarkdownStr MsgType_ = "markdown"
|
|
||||||
ActionCardStr MsgType_ = "actionCard"
|
|
||||||
FeedCardStr MsgType_ = "feedCard"
|
|
||||||
)
|
|
@ -0,0 +1,27 @@
|
|||||||
|
package dingtalk
|
||||||
|
|
||||||
|
// Params 请求参数
|
||||||
|
type Params map[string]interface{}
|
||||||
|
|
||||||
|
func NewParams() Params {
|
||||||
|
p := make(Params)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *App) NewParamsWith(params ...Params) Params {
|
||||||
|
p := make(Params)
|
||||||
|
for _, v := range params {
|
||||||
|
p.SetParams(v)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Params) Set(key string, value interface{}) {
|
||||||
|
p[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Params) SetParams(params Params) {
|
||||||
|
for key, value := range params {
|
||||||
|
p[key] = value
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package dingtalk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RobotSendResult struct {
|
||||||
|
Errcode int64 `json:"errcode"`
|
||||||
|
Errmsg string `json:"errmsg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RobotSend 自定义机器人
|
||||||
|
// https://open.dingtalk.com/document/group/custom-robot-access
|
||||||
|
func (app *App) RobotSend(notMustParams ...Params) (body []byte, err error) {
|
||||||
|
// 参数
|
||||||
|
params := app.NewParamsWith(notMustParams...)
|
||||||
|
// 时间
|
||||||
|
timestamp := time.Now().UnixNano() / 1e6
|
||||||
|
// 请求
|
||||||
|
body, err = app.request(fmt.Sprintf("https://oapi.dingtalk.com/robot/send?access_token=%s×tamp=%d&sign=%s", app.AccessToken, timestamp, app.sign(timestamp)), params, http.MethodPost)
|
||||||
|
return body, err
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package dingtalk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (app *App) sign(t int64) string {
|
||||||
|
secStr := fmt.Sprintf("%d\n%s", t, app.Secret)
|
||||||
|
hmac256 := hmac.New(sha256.New, []byte(app.Secret))
|
||||||
|
hmac256.Write([]byte(secStr))
|
||||||
|
result := hmac256.Sum(nil)
|
||||||
|
return base64.StdEncoding.EncodeToString(result)
|
||||||
|
}
|
Loading…
Reference in new issue