wechat-corp-account.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package channel
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "message-pusher/common"
  8. "message-pusher/model"
  9. "net/http"
  10. "time"
  11. )
  12. type wechatCorpAccountResponse struct {
  13. ErrorCode int `json:"errcode"`
  14. ErrorMessage string `json:"errmsg"`
  15. AccessToken string `json:"access_token"`
  16. ExpiresIn int `json:"expires_in"`
  17. }
  18. type WeChatCorpAccountTokenStoreItem struct {
  19. CorpId string
  20. AgentSecret string
  21. AgentId string
  22. AccessToken string
  23. }
  24. func (i *WeChatCorpAccountTokenStoreItem) Key() string {
  25. return i.CorpId + i.AgentId + i.AgentSecret
  26. }
  27. func (i *WeChatCorpAccountTokenStoreItem) IsShared() bool {
  28. return model.DB.Where("wechat_corp_account_id = ? and wechat_corp_account_agent_secret = ? and wechat_corp_account_agent_id = ?",
  29. i.CorpId, i.AgentSecret, i.AgentId).Find(&model.User{}).RowsAffected != 1
  30. }
  31. func (i *WeChatCorpAccountTokenStoreItem) IsFilled() bool {
  32. return i.CorpId != "" && i.AgentSecret != "" && i.AgentId != ""
  33. }
  34. func (i *WeChatCorpAccountTokenStoreItem) Token() string {
  35. return i.AccessToken
  36. }
  37. func (i *WeChatCorpAccountTokenStoreItem) Refresh() {
  38. // https://work.weixin.qq.com/api/doc/90000/90135/91039
  39. client := http.Client{
  40. Timeout: 5 * time.Second,
  41. }
  42. req, err := http.NewRequest("GET", fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s",
  43. i.CorpId, i.AgentSecret), nil)
  44. if err != nil {
  45. common.SysError(err.Error())
  46. return
  47. }
  48. responseData, err := client.Do(req)
  49. if err != nil {
  50. common.SysError("failed to refresh access token: " + err.Error())
  51. return
  52. }
  53. defer responseData.Body.Close()
  54. var res wechatCorpAccountResponse
  55. err = json.NewDecoder(responseData.Body).Decode(&res)
  56. if err != nil {
  57. common.SysError("failed to decode wechatCorpAccountResponse: " + err.Error())
  58. return
  59. }
  60. if res.ErrorCode != 0 {
  61. common.SysError(res.ErrorMessage)
  62. return
  63. }
  64. i.AccessToken = res.AccessToken
  65. common.SysLog("access token refreshed")
  66. }
  67. type wechatCorpMessageRequest struct {
  68. MessageType string `json:"msgtype"`
  69. ToUser string `json:"touser"`
  70. AgentId string `json:"agentid"`
  71. TextCard struct {
  72. Title string `json:"title"`
  73. Description string `json:"description"`
  74. URL string `json:"url"`
  75. } `json:"textcard"`
  76. Text struct {
  77. Content string `json:"content"`
  78. } `json:"text"`
  79. Markdown struct {
  80. Content string `json:"content"`
  81. } `json:"markdown"`
  82. }
  83. type wechatCorpMessageResponse struct {
  84. ErrorCode int `json:"errcode"`
  85. ErrorMessage string `json:"errmsg"`
  86. }
  87. func SendWeChatCorpMessage(message *model.Message, user *model.User) error {
  88. if user.WeChatCorpAccountId == "" {
  89. return errors.New("未配置微信企业号消息推送方式")
  90. }
  91. // https://developer.work.weixin.qq.com/document/path/90236
  92. messageRequest := wechatCorpMessageRequest{
  93. ToUser: user.WeChatCorpAccountUserId,
  94. AgentId: user.WeChatCorpAccountAgentId,
  95. }
  96. if message.To != "" {
  97. messageRequest.ToUser = message.To
  98. }
  99. if message.Content == "" {
  100. if message.Title == "" {
  101. messageRequest.MessageType = "text"
  102. messageRequest.Text.Content = message.Description
  103. } else {
  104. messageRequest.MessageType = "textcard"
  105. messageRequest.TextCard.Title = message.Title
  106. messageRequest.TextCard.Description = message.Description
  107. messageRequest.TextCard.URL = common.ServerAddress
  108. }
  109. } else {
  110. if user.WeChatCorpAccountClientType == "plugin" {
  111. messageRequest.MessageType = "textcard"
  112. messageRequest.TextCard.Title = message.Title
  113. messageRequest.TextCard.Description = message.Description
  114. messageRequest.TextCard.URL = message.URL
  115. } else {
  116. messageRequest.MessageType = "markdown"
  117. messageRequest.Markdown.Content = message.Content
  118. }
  119. }
  120. jsonData, err := json.Marshal(messageRequest)
  121. if err != nil {
  122. return err
  123. }
  124. key := fmt.Sprintf("%s%s%s", user.WeChatCorpAccountId, user.WeChatCorpAccountAgentId, user.WeChatCorpAccountAgentSecret)
  125. accessToken := TokenStoreGetToken(key)
  126. resp, err := http.Post(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s", accessToken), "application/json",
  127. bytes.NewBuffer(jsonData))
  128. if err != nil {
  129. return err
  130. }
  131. var res wechatCorpMessageResponse
  132. err = json.NewDecoder(resp.Body).Decode(&res)
  133. if err != nil {
  134. return err
  135. }
  136. if res.ErrorCode != 0 {
  137. return errors.New(res.ErrorMessage)
  138. }
  139. return nil
  140. }