draft.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. package draft
  2. import (
  3. "fmt"
  4. "github.com/silenceper/wechat/v2/officialaccount/context"
  5. "github.com/silenceper/wechat/v2/util"
  6. )
  7. const (
  8. addURL = "https://api.weixin.qq.com/cgi-bin/draft/add" // 新建草稿
  9. getURL = "https://api.weixin.qq.com/cgi-bin/draft/get" // 获取草稿
  10. deleteURL = "https://api.weixin.qq.com/cgi-bin/draft/delete" // 删除草稿
  11. updateURL = "https://api.weixin.qq.com/cgi-bin/draft/update" // 修改草稿
  12. countURL = "https://api.weixin.qq.com/cgi-bin/draft/count" // 获取草稿总数
  13. paginateURL = "https://api.weixin.qq.com/cgi-bin/draft/batchget" // 获取草稿列表
  14. )
  15. // Draft 草稿箱
  16. type Draft struct {
  17. *context.Context
  18. }
  19. // NewDraft init
  20. func NewDraft(ctx *context.Context) *Draft {
  21. return &Draft{
  22. Context: ctx,
  23. }
  24. }
  25. // Article 草稿
  26. type Article struct {
  27. Title string `json:"title"` // 标题
  28. Author string `json:"author"` // 作者
  29. Digest string `json:"digest"` // 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空。
  30. Content string `json:"content"` // 图文消息的具体内容,支持 HTML 标签,必须少于 2 万字符,小于 1M,且去除 JS
  31. ContentSourceURL string `json:"content_source_url"` // 图文消息的原文地址,即点击“阅读原文”后的 URL
  32. ThumbMediaID string `json:"thumb_media_id"` // 图文消息的封面图片素材 id(必须是永久 MediaID)
  33. ShowCoverPic uint `json:"show_cover_pic"` // 是否显示封面,0 为 false,即不显示,1 为 true,即显示 (默认)
  34. NeedOpenComment uint `json:"need_open_comment"` // 是否打开评论,0 不打开 (默认),1 打开
  35. OnlyFansCanComment uint `json:"only_fans_can_comment"` // 是否粉丝才可评论,0 所有人可评论 (默认),1 粉丝才可评论
  36. }
  37. // AddDraft 新建草稿
  38. func (draft *Draft) AddDraft(articles []*Article) (mediaID string, err error) {
  39. accessToken, err := draft.GetAccessToken()
  40. if err != nil {
  41. return
  42. }
  43. var req struct {
  44. Articles []*Article `json:"articles"`
  45. }
  46. req.Articles = articles
  47. uri := fmt.Sprintf("%s?access_token=%s", addURL, accessToken)
  48. response, err := util.PostJSON(uri, req)
  49. if err != nil {
  50. return
  51. }
  52. var res struct {
  53. util.CommonError
  54. MediaID string `json:"media_id"`
  55. }
  56. err = util.DecodeWithError(response, &res, "AddDraft")
  57. return res.MediaID, err
  58. }
  59. // GetDraft 获取草稿
  60. func (draft *Draft) GetDraft(mediaID string) (articles []*Article, err error) {
  61. accessToken, err := draft.GetAccessToken()
  62. if err != nil {
  63. return
  64. }
  65. var req struct {
  66. MediaID string `json:"media_id"`
  67. }
  68. req.MediaID = mediaID
  69. uri := fmt.Sprintf("%s?access_token=%s", getURL, accessToken)
  70. response, err := util.PostJSON(uri, req)
  71. if err != nil {
  72. return
  73. }
  74. var res struct {
  75. util.CommonError
  76. NewsItem []*Article `json:"news_item"`
  77. }
  78. err = util.DecodeWithError(response, &res, "GetDraft")
  79. return res.NewsItem, err
  80. }
  81. // DeleteDraft 删除草稿
  82. func (draft *Draft) DeleteDraft(mediaID string) (err error) {
  83. accessToken, err := draft.GetAccessToken()
  84. if err != nil {
  85. return
  86. }
  87. var req struct {
  88. MediaID string `json:"media_id"`
  89. }
  90. req.MediaID = mediaID
  91. var response []byte
  92. uri := fmt.Sprintf("%s?access_token=%s", deleteURL, accessToken)
  93. response, err = util.PostJSON(uri, req)
  94. if err != nil {
  95. return
  96. }
  97. err = util.DecodeWithCommonError(response, "DeleteDraft")
  98. return
  99. }
  100. // UpdateDraft 修改草稿
  101. // index 要更新的文章在图文消息中的位置(多图文消息时,此字段才有意义),第一篇为 0
  102. func (draft *Draft) UpdateDraft(article *Article, mediaID string, index uint) (err error) {
  103. accessToken, err := draft.GetAccessToken()
  104. if err != nil {
  105. return
  106. }
  107. var req struct {
  108. MediaID string `json:"media_id"`
  109. Index uint `json:"index"`
  110. Article *Article `json:"articles"`
  111. }
  112. req.MediaID = mediaID
  113. req.Index = index
  114. req.Article = article
  115. uri := fmt.Sprintf("%s?access_token=%s", updateURL, accessToken)
  116. var response []byte
  117. response, err = util.PostJSON(uri, req)
  118. if err != nil {
  119. return
  120. }
  121. err = util.DecodeWithCommonError(response, "UpdateDraft")
  122. return
  123. }
  124. // CountDraft 获取草稿总数
  125. func (draft *Draft) CountDraft() (total uint, err error) {
  126. accessToken, err := draft.GetAccessToken()
  127. if err != nil {
  128. return
  129. }
  130. var response []byte
  131. uri := fmt.Sprintf("%s?access_token=%s", countURL, accessToken)
  132. response, err = util.HTTPGet(uri)
  133. if err != nil {
  134. return
  135. }
  136. var res struct {
  137. util.CommonError
  138. Total uint `json:"total_count"`
  139. }
  140. err = util.DecodeWithError(response, &res, "CountDraft")
  141. return res.Total, err
  142. }
  143. // ArticleList 草稿列表
  144. type ArticleList struct {
  145. util.CommonError
  146. TotalCount int64 `json:"total_count"` // 草稿素材的总数
  147. ItemCount int64 `json:"item_count"` // 本次调用获取的素材的数量
  148. Item []ArticleListItem `json:"item"`
  149. }
  150. // ArticleListItem 用于 ArticleList 的 item 节点
  151. type ArticleListItem struct {
  152. MediaID string `json:"media_id"` // 图文消息的 id
  153. Content ArticleListContent `json:"content"` // 内容
  154. UpdateTime int64 `json:"update_time"` // 这篇图文消息素材的最后更新时间
  155. }
  156. // ArticleListContent 用于 ArticleListItem 的 content 节点
  157. type ArticleListContent struct {
  158. NewsItem []Article `json:"news_item"` // 这篇图文消息素材的内容
  159. }
  160. // PaginateDraft 获取草稿列表
  161. func (draft *Draft) PaginateDraft(offset, count int64, noReturnContent bool) (list ArticleList, err error) {
  162. accessToken, err := draft.GetAccessToken()
  163. if err != nil {
  164. return
  165. }
  166. var req struct {
  167. Count int64 `json:"count"`
  168. Offset int64 `json:"offset"`
  169. NoReturnContent bool `json:"no_content"`
  170. }
  171. req.Count = count
  172. req.Offset = offset
  173. req.NoReturnContent = noReturnContent
  174. var response []byte
  175. uri := fmt.Sprintf("%s?access_token=%s", paginateURL, accessToken)
  176. response, err = util.PostJSON(uri, req)
  177. if err != nil {
  178. return
  179. }
  180. err = util.DecodeWithError(response, &list, "PaginateDraft")
  181. return
  182. }