You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

client.go 4.2 kB

3 years ago
3 years ago
3 years ago
3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package wechat
  2. import (
  3. "code.gitea.io/gitea/modules/log"
  4. "code.gitea.io/gitea/modules/setting"
  5. "encoding/json"
  6. "fmt"
  7. "github.com/go-resty/resty/v2"
  8. "strconv"
  9. "time"
  10. )
  11. var (
  12. client *resty.Client
  13. )
  14. const (
  15. GRANT_TYPE = "client_credential"
  16. ACCESS_TOKEN_PATH = "/cgi-bin/token"
  17. QR_CODE_PATH = "/cgi-bin/qrcode/create"
  18. GET_MATERIAL_PATH = "/cgi-bin/material/batchget_material"
  19. ACTION_QR_STR_SCENE = "QR_STR_SCENE"
  20. ERR_CODE_ACCESSTOKEN_EXPIRE = 42001
  21. ERR_CODE_ACCESSTOKEN_INVALID = 40001
  22. )
  23. type AccessTokenResponse struct {
  24. Access_token string
  25. Expires_in int
  26. }
  27. type QRCodeResponse struct {
  28. Ticket string `json:"ticket"`
  29. Expire_Seconds int `json:"expire_seconds"`
  30. Url string `json:"url"`
  31. }
  32. type QRCodeRequest struct {
  33. Action_name string `json:"action_name"`
  34. Action_info ActionInfo `json:"action_info"`
  35. Expire_seconds int `json:"expire_seconds"`
  36. }
  37. type MaterialRequest struct {
  38. Type string `json:"type"`
  39. Offset int `json:"offset"`
  40. Count int `json:"count"`
  41. }
  42. type ActionInfo struct {
  43. Scene Scene `json:"scene"`
  44. }
  45. type Scene struct {
  46. Scene_str string `json:"scene_str"`
  47. }
  48. type ErrorResponse struct {
  49. Errcode int
  50. Errmsg string
  51. }
  52. func getWechatRestyClient() *resty.Client {
  53. if client == nil {
  54. client = resty.New()
  55. client.SetTimeout(time.Duration(setting.WechatApiTimeoutSeconds) * time.Second)
  56. }
  57. return client
  58. }
  59. // api doc:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
  60. func callAccessToken() *AccessTokenResponse {
  61. client := getWechatRestyClient()
  62. var result AccessTokenResponse
  63. _, err := client.R().
  64. SetQueryParam("grant_type", GRANT_TYPE).
  65. SetQueryParam("appid", setting.WechatAppId).
  66. SetQueryParam("secret", setting.WechatAppSecret).
  67. SetResult(&result).
  68. Get(setting.WechatApiHost + ACCESS_TOKEN_PATH)
  69. if err != nil {
  70. log.Error("get wechat access token failed,e=%v", err)
  71. return nil
  72. }
  73. return &result
  74. }
  75. //callQRCodeCreate call the wechat api to create qr-code,
  76. // api doc: https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
  77. func callQRCodeCreate(sceneStr string) (*QRCodeResponse, bool) {
  78. client := getWechatRestyClient()
  79. body := &QRCodeRequest{
  80. Action_name: ACTION_QR_STR_SCENE,
  81. Action_info: ActionInfo{Scene: Scene{Scene_str: sceneStr}},
  82. Expire_seconds: setting.WechatQRCodeExpireSeconds,
  83. }
  84. bodyJson, _ := json.Marshal(body)
  85. var result QRCodeResponse
  86. r, err := client.R().
  87. SetHeader("Content-Type", "application/json").
  88. SetQueryParam("access_token", GetWechatAccessToken()).
  89. SetBody(bodyJson).
  90. SetResult(&result).
  91. Post(setting.WechatApiHost + QR_CODE_PATH)
  92. if err != nil {
  93. log.Error("create QR code failed,e=%v", err)
  94. return nil, false
  95. }
  96. errCode := getErrorCodeFromResponse(r)
  97. if errCode == ERR_CODE_ACCESSTOKEN_EXPIRE || errCode == ERR_CODE_ACCESSTOKEN_INVALID {
  98. return nil, true
  99. }
  100. if result.Url == "" {
  101. return nil, false
  102. }
  103. log.Info("%v", r)
  104. return &result, false
  105. }
  106. //getMaterial
  107. // api doc: https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Get_materials_list.html
  108. func getMaterial(mType string, offset, count int) (interface{}, bool) {
  109. client := getWechatRestyClient()
  110. body := &MaterialRequest{
  111. Type: mType,
  112. Offset: offset,
  113. Count: count,
  114. }
  115. bodyJson, _ := json.Marshal(body)
  116. r, err := client.R().
  117. SetHeader("Content-Type", "application/json").
  118. SetQueryParam("access_token", GetWechatAccessToken()).
  119. SetBody(bodyJson).
  120. Post(setting.WechatApiHost + GET_MATERIAL_PATH)
  121. if err != nil {
  122. log.Error("create QR code failed,e=%v", err)
  123. return nil, false
  124. }
  125. a := r.Body()
  126. resultMap := make(map[string]interface{}, 0)
  127. json.Unmarshal(a, &resultMap)
  128. errcode := resultMap["errcode"]
  129. if errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_EXPIRE) || errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_INVALID) {
  130. return nil, true
  131. }
  132. log.Info("%v", r)
  133. return &resultMap, false
  134. }
  135. func getErrorCodeFromResponse(r *resty.Response) int {
  136. a := r.Body()
  137. resultMap := make(map[string]interface{}, 0)
  138. json.Unmarshal(a, &resultMap)
  139. code := resultMap["errcode"]
  140. if code == nil {
  141. return -1
  142. }
  143. c, _ := strconv.Atoi(fmt.Sprint(code))
  144. return c
  145. }