mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-04 12:52:27 +08:00
439 lines
14 KiB
Go
439 lines
14 KiB
Go
package subscribe
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
|
||
"github.com/silenceper/wechat/v2/miniprogram/context"
|
||
"github.com/silenceper/wechat/v2/util"
|
||
)
|
||
|
||
const (
|
||
// 发送订阅消息
|
||
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
|
||
subscribeSendURL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send"
|
||
// 获取当前帐号下的个人模板列表
|
||
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.getTemplateList.html
|
||
getTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate"
|
||
// 添加订阅模板
|
||
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.addTemplate.html
|
||
addTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate"
|
||
// 删除私有模板
|
||
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.deleteTemplate.html
|
||
delTemplateURL = "https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate"
|
||
// 统一服务消息
|
||
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/uniform-message/uniformMessage.send.html
|
||
uniformMessageSend = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send"
|
||
// getCategoryURL 获取类目
|
||
getCategoryURL = "https://api.weixin.qq.com/wxaapi/newtmpl/getcategory?access_token=%s"
|
||
// getPubTemplateKeyWordsByIDURL 获取关键词列表
|
||
getPubTemplateKeyWordsByIDURL = "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatekeywords?access_token=%s&tid=%s"
|
||
// getPubTemplateTitleListURL 获取所属类目下的公共模板
|
||
getPubTemplateTitleListURL = "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatetitles?access_token=%s&ids=%s&start=%d&limit=%d"
|
||
// setUserNotifyURL 激活与更新服务卡片
|
||
setUserNotifyURL = "https://api.weixin.qq.com/wxa/set_user_notify?access_token=%s"
|
||
// setUserNotifyExtURL 更新服务卡片扩展信息
|
||
setUserNotifyExtURL = "https://api.weixin.qq.com/wxa/set_user_notifyext?access_token=%s"
|
||
// getUserNotifyURL 查询服务卡片状态
|
||
getUserNotifyURL = "https://api.weixin.qq.com/wxa/get_user_notify?access_token=%s"
|
||
)
|
||
|
||
// Subscribe 订阅消息
|
||
type Subscribe struct {
|
||
*context.Context
|
||
}
|
||
|
||
// NewSubscribe 实例化
|
||
func NewSubscribe(ctx *context.Context) *Subscribe {
|
||
return &Subscribe{Context: ctx}
|
||
}
|
||
|
||
// Message 订阅消息请求参数
|
||
type Message struct {
|
||
ToUser string `json:"touser"` // 必选,接收者(用户)的 openid
|
||
TemplateID string `json:"template_id"` // 必选,所需下发的订阅模板id
|
||
Page string `json:"page"` // 可选,点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
|
||
Data map[string]*DataItem `json:"data"` // 必选, 模板内容
|
||
MiniprogramState string `json:"miniprogram_state"` // 可选,跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
|
||
Lang string `json:"lang"` // 入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN
|
||
}
|
||
|
||
// DataItem 模版内某个 .DATA 的值
|
||
type DataItem struct {
|
||
Value interface{} `json:"value"`
|
||
Color string `json:"color"`
|
||
}
|
||
|
||
// TemplateItem template item
|
||
type TemplateItem struct {
|
||
PriTmplID string `json:"priTmplId"`
|
||
Title string `json:"title"`
|
||
Content string `json:"content"`
|
||
Example string `json:"example"`
|
||
Type int64 `json:"type"`
|
||
KeywordEnumValueList []KeywordEnumValue `json:"keywordEnumValueList"`
|
||
}
|
||
|
||
// KeywordEnumValue 枚举参数值范围
|
||
type KeywordEnumValue struct {
|
||
EnumValueList []string `json:"enumValueList"`
|
||
KeywordCode string `json:"keywordCode"`
|
||
}
|
||
|
||
// TemplateList template list
|
||
type TemplateList struct {
|
||
util.CommonError
|
||
Data []TemplateItem `json:"data"`
|
||
}
|
||
|
||
// resTemplateSend 发送获取 msg id
|
||
type resTemplateSend struct {
|
||
util.CommonError
|
||
|
||
MsgID int64 `json:"msgid"`
|
||
}
|
||
|
||
// Send 发送订阅消息
|
||
func (s *Subscribe) Send(msg *Message) (err error) {
|
||
var accessToken string
|
||
accessToken, err = s.GetAccessToken()
|
||
if err != nil {
|
||
return
|
||
}
|
||
uri := fmt.Sprintf("%s?access_token=%s", subscribeSendURL, accessToken)
|
||
response, err := util.PostJSON(uri, msg)
|
||
if err != nil {
|
||
return
|
||
}
|
||
return util.DecodeWithCommonError(response, "Send")
|
||
}
|
||
|
||
// SendGetMsgID 发送订阅消息返回 msgid
|
||
func (s *Subscribe) SendGetMsgID(msg *Message) (msgID int64, err error) {
|
||
var accessToken string
|
||
accessToken, err = s.GetAccessToken()
|
||
if err != nil {
|
||
return
|
||
}
|
||
uri := fmt.Sprintf("%s?access_token=%s", subscribeSendURL, accessToken)
|
||
response, err := util.PostJSON(uri, msg)
|
||
if err != nil {
|
||
return
|
||
}
|
||
|
||
var result resTemplateSend
|
||
if err = json.Unmarshal(response, &result); err != nil {
|
||
return
|
||
}
|
||
if result.ErrCode != 0 {
|
||
err = fmt.Errorf("template msg send error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
|
||
return
|
||
}
|
||
|
||
msgID = result.MsgID
|
||
|
||
return
|
||
}
|
||
|
||
// ListTemplates 获取当前帐号下的个人模板列表
|
||
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.getTemplateList.html
|
||
func (s *Subscribe) ListTemplates() (*TemplateList, error) {
|
||
accessToken, err := s.GetAccessToken()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
uri := fmt.Sprintf("%s?access_token=%s", getTemplateURL, accessToken)
|
||
response, err := util.HTTPGet(uri)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
templateList := TemplateList{}
|
||
err = util.DecodeWithError(response, &templateList, "ListTemplates")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &templateList, nil
|
||
}
|
||
|
||
// UniformMessage 统一服务消息
|
||
type UniformMessage struct {
|
||
ToUser string `json:"touser"`
|
||
WeappTemplateMsg struct {
|
||
TemplateID string `json:"template_id"`
|
||
Page string `json:"page"`
|
||
FormID string `json:"form_id"`
|
||
Data map[string]*DataItem `json:"data"`
|
||
EmphasisKeyword string `json:"emphasis_keyword"`
|
||
} `json:"weapp_template_msg"`
|
||
MpTemplateMsg struct {
|
||
Appid string `json:"appid"`
|
||
TemplateID string `json:"template_id"`
|
||
URL string `json:"url"`
|
||
Miniprogram struct {
|
||
Appid string `json:"appid"`
|
||
Pagepath string `json:"pagepath"`
|
||
} `json:"miniprogram"`
|
||
Data map[string]*DataItem `json:"data"`
|
||
} `json:"mp_template_msg"`
|
||
}
|
||
|
||
// UniformSend 发送统一服务消息
|
||
func (s *Subscribe) UniformSend(msg *UniformMessage) (err error) {
|
||
var accessToken string
|
||
accessToken, err = s.GetAccessToken()
|
||
if err != nil {
|
||
return
|
||
}
|
||
uri := fmt.Sprintf("%s?access_token=%s", uniformMessageSend, accessToken)
|
||
response, err := util.PostJSON(uri, msg)
|
||
if err != nil {
|
||
return
|
||
}
|
||
return util.DecodeWithCommonError(response, "UniformSend")
|
||
}
|
||
|
||
type resSubscribeAdd struct {
|
||
util.CommonError
|
||
|
||
TemplateID string `json:"priTmplId"`
|
||
}
|
||
|
||
// Add 添加订阅消息模板
|
||
func (s *Subscribe) Add(ShortID string, kidList []int, sceneDesc string) (templateID string, err error) {
|
||
var accessToken string
|
||
accessToken, err = s.GetAccessToken()
|
||
if err != nil {
|
||
return
|
||
}
|
||
var msg = struct {
|
||
TemplateIDShort string `json:"tid"`
|
||
SceneDesc string `json:"sceneDesc"`
|
||
KidList []int `json:"kidList"`
|
||
}{TemplateIDShort: ShortID, SceneDesc: sceneDesc, KidList: kidList}
|
||
uri := fmt.Sprintf("%s?access_token=%s", addTemplateURL, accessToken)
|
||
var response []byte
|
||
response, err = util.PostJSON(uri, msg)
|
||
if err != nil {
|
||
return
|
||
}
|
||
var result resSubscribeAdd
|
||
err = util.DecodeWithError(response, &result, "AddSubscribe")
|
||
return result.TemplateID, err
|
||
}
|
||
|
||
// Delete 删除私有模板
|
||
func (s *Subscribe) Delete(templateID string) (err error) {
|
||
var accessToken string
|
||
accessToken, err = s.GetAccessToken()
|
||
if err != nil {
|
||
return
|
||
}
|
||
var msg = struct {
|
||
TemplateID string `json:"priTmplId"`
|
||
}{TemplateID: templateID}
|
||
uri := fmt.Sprintf("%s?access_token=%s", delTemplateURL, accessToken)
|
||
var response []byte
|
||
response, err = util.PostJSON(uri, msg)
|
||
if err != nil {
|
||
return
|
||
}
|
||
return util.DecodeWithCommonError(response, "DeleteSubscribe")
|
||
}
|
||
|
||
// GetCategoryResponse 获取类目响应
|
||
type GetCategoryResponse struct {
|
||
util.CommonError
|
||
Data []Category `json:"data"`
|
||
}
|
||
|
||
// Category 类目
|
||
type Category struct {
|
||
ID int64 `json:"id"`
|
||
Name string `json:"name"`
|
||
}
|
||
|
||
// GetCategory 获取类目
|
||
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/getCategory.html
|
||
func (s *Subscribe) GetCategory() ([]Category, error) {
|
||
var (
|
||
accessToken string
|
||
err error
|
||
)
|
||
if accessToken, err = s.GetAccessToken(); err != nil {
|
||
return nil, err
|
||
}
|
||
var response []byte
|
||
if response, err = util.HTTPGet(fmt.Sprintf(getCategoryURL, accessToken)); err != nil {
|
||
return nil, err
|
||
}
|
||
result := &GetCategoryResponse{}
|
||
err = util.DecodeWithError(response, result, "GetCategory")
|
||
return result.Data, err
|
||
}
|
||
|
||
// GetPubTemplateKeywordsByIDResponse 获取关键词列表响应
|
||
type GetPubTemplateKeywordsByIDResponse struct {
|
||
util.CommonError
|
||
Count int64 `json:"count"`
|
||
Data []PubTemplateKeywords `json:"data"`
|
||
}
|
||
|
||
// PubTemplateKeywords 关键词
|
||
type PubTemplateKeywords struct {
|
||
KID int64 `json:"kid"`
|
||
Name string `json:"name"`
|
||
Example string `json:"example"`
|
||
Rule string `json:"rule"`
|
||
}
|
||
|
||
// GetPubTemplateKeywordsByID 获取关键词列表
|
||
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/getPubTemplateKeyWordsById.html
|
||
func (s *Subscribe) GetPubTemplateKeywordsByID(tid string) (*GetPubTemplateKeywordsByIDResponse, error) {
|
||
var (
|
||
accessToken string
|
||
err error
|
||
)
|
||
if accessToken, err = s.GetAccessToken(); err != nil {
|
||
return nil, err
|
||
}
|
||
var response []byte
|
||
if response, err = util.HTTPGet(fmt.Sprintf(getPubTemplateKeyWordsByIDURL, accessToken, tid)); err != nil {
|
||
return nil, err
|
||
}
|
||
result := &GetPubTemplateKeywordsByIDResponse{}
|
||
err = util.DecodeWithError(response, result, "GetPubTemplateKeywordsByID")
|
||
return result, err
|
||
}
|
||
|
||
// GetPubTemplateTitleListRequest 获取所属类目下的公共模板请求
|
||
type GetPubTemplateTitleListRequest struct {
|
||
Start int64
|
||
Limit int64
|
||
IDs string
|
||
}
|
||
|
||
// GetPubTemplateTitleListResponse 获取所属类目下的公共模板响应
|
||
type GetPubTemplateTitleListResponse struct {
|
||
util.CommonError
|
||
Count int64 `json:"count"`
|
||
Data []PubTemplateTitle `json:"data"`
|
||
}
|
||
|
||
// PubTemplateTitle 模板标题
|
||
type PubTemplateTitle struct {
|
||
Type int64 `json:"type"`
|
||
TID string `json:"tid"`
|
||
Title string `json:"title"`
|
||
CategoryID string `json:"categoryId"`
|
||
}
|
||
|
||
// GetPubTemplateTitleList 获取所属类目下的公共模板
|
||
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/getPubTemplateTitleList.html
|
||
func (s *Subscribe) GetPubTemplateTitleList(req *GetPubTemplateTitleListRequest) (*GetPubTemplateTitleListResponse, error) {
|
||
var (
|
||
accessToken string
|
||
err error
|
||
)
|
||
if accessToken, err = s.GetAccessToken(); err != nil {
|
||
return nil, err
|
||
}
|
||
var response []byte
|
||
if response, err = util.HTTPGet(fmt.Sprintf(getPubTemplateTitleListURL, accessToken, req.IDs, req.Start, req.Limit)); err != nil {
|
||
return nil, err
|
||
}
|
||
result := &GetPubTemplateTitleListResponse{}
|
||
err = util.DecodeWithError(response, result, "GetPubTemplateTitleList")
|
||
return result, err
|
||
}
|
||
|
||
// SetUserNotifyRequest 激活与更新服务卡片请求
|
||
type SetUserNotifyRequest struct {
|
||
OpenID string `json:"openid"`
|
||
NotifyType int64 `json:"notify_type"`
|
||
NotifyCode string `json:"notify_code"`
|
||
ContentJSON string `json:"content_json"`
|
||
CheckJSON string `json:"check_json,omitempty"`
|
||
}
|
||
|
||
// SetUserNotify 激活与更新服务卡片
|
||
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/setUserNotify.html
|
||
func (s *Subscribe) SetUserNotify(req *SetUserNotifyRequest) error {
|
||
var (
|
||
accessToken string
|
||
err error
|
||
)
|
||
if accessToken, err = s.GetAccessToken(); err != nil {
|
||
return err
|
||
}
|
||
var response []byte
|
||
if response, err = util.PostJSON(fmt.Sprintf(setUserNotifyURL, accessToken), req); err != nil {
|
||
return err
|
||
}
|
||
return util.DecodeWithCommonError(response, "SetUserNotify")
|
||
}
|
||
|
||
// SetUserNotifyExtRequest 更新服务卡片扩展信息请求
|
||
type SetUserNotifyExtRequest struct {
|
||
OpenID string `json:"openid"`
|
||
NotifyType int64 `json:"notify_type"`
|
||
NotifyCode string `json:"notify_code"`
|
||
ExtJSON string `json:"ext_json"`
|
||
}
|
||
|
||
// SetUserNotifyExt 更新服务卡片扩展信息
|
||
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/setUserNotifyExt.html
|
||
func (s *Subscribe) SetUserNotifyExt(req *SetUserNotifyExtRequest) error {
|
||
var (
|
||
accessToken string
|
||
err error
|
||
)
|
||
if accessToken, err = s.GetAccessToken(); err != nil {
|
||
return err
|
||
}
|
||
var response []byte
|
||
if response, err = util.PostJSON(fmt.Sprintf(setUserNotifyExtURL, accessToken), req); err != nil {
|
||
return err
|
||
}
|
||
return util.DecodeWithCommonError(response, "SetUserNotifyExt")
|
||
}
|
||
|
||
// GetUserNotifyRequest 查询服务卡片状态请求
|
||
type GetUserNotifyRequest struct {
|
||
OpenID string `json:"openid"`
|
||
NotifyType int64 `json:"notify_type"`
|
||
NotifyCode string `json:"notify_code"`
|
||
}
|
||
|
||
// GetUserNotifyResponse 查询服务卡片状态响应
|
||
type GetUserNotifyResponse struct {
|
||
util.CommonError
|
||
NotifyInfo NotifyInfo `json:"notify_info"`
|
||
}
|
||
|
||
// NotifyInfo 卡片状态
|
||
type NotifyInfo struct {
|
||
NotifyType int64 `json:"notify_type"`
|
||
ContentJSON string `json:"content_json"`
|
||
CodeState int64 `json:"code_state"`
|
||
CodeExpireTime int64 `json:"code_expire_time"`
|
||
}
|
||
|
||
// GetUserNotify 查询服务卡片状态
|
||
// see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/getUserNotify.html
|
||
func (s *Subscribe) GetUserNotify(req *GetUserNotifyRequest) (*GetUserNotifyResponse, error) {
|
||
var (
|
||
accessToken string
|
||
err error
|
||
)
|
||
if accessToken, err = s.GetAccessToken(); err != nil {
|
||
return nil, err
|
||
}
|
||
var response []byte
|
||
if response, err = util.PostJSON(fmt.Sprintf(getUserNotifyURL, accessToken), req); err != nil {
|
||
return nil, err
|
||
}
|
||
result := &GetUserNotifyResponse{}
|
||
err = util.DecodeWithError(response, result, "GetUserNotify")
|
||
return result, err
|
||
}
|