From f767b72872afdfcc023c057de5c790332a9004c2 Mon Sep 17 00:00:00 2001 From: George Wang Date: Mon, 6 Sep 2021 20:53:29 +0800 Subject: [PATCH 01/84] =?UTF-8?q?=E5=A2=9E=E5=8A=A0urllink=20(#465)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 增加urllink * urllink.Generate返回string作为结果 --- miniprogram/miniprogram.go | 6 +++ miniprogram/urllink/urllink.go | 71 ++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 miniprogram/urllink/urllink.go diff --git a/miniprogram/miniprogram.go b/miniprogram/miniprogram.go index 7222848..ab32996 100644 --- a/miniprogram/miniprogram.go +++ b/miniprogram/miniprogram.go @@ -13,6 +13,7 @@ import ( "github.com/silenceper/wechat/v2/miniprogram/shortlink" "github.com/silenceper/wechat/v2/miniprogram/subscribe" "github.com/silenceper/wechat/v2/miniprogram/tcb" + "github.com/silenceper/wechat/v2/miniprogram/urllink" "github.com/silenceper/wechat/v2/miniprogram/werun" ) @@ -86,6 +87,11 @@ func (miniProgram *MiniProgram) GetContentSecurity() *content.Content { return content.NewContent(miniProgram.ctx) } +// GetURLLink 小程序URL Link接口 +func (miniProgram *MiniProgram) GetURLLink() *urllink.URLLink { + return urllink.NewURLLink(miniProgram.ctx) +} + // GetShortLink 小程序短链接口 func (miniProgram *MiniProgram) GetShortLink() *shortlink.ShortLink { return shortlink.NewShortLink(miniProgram.ctx) diff --git a/miniprogram/urllink/urllink.go b/miniprogram/urllink/urllink.go new file mode 100644 index 0000000..c043ac2 --- /dev/null +++ b/miniprogram/urllink/urllink.go @@ -0,0 +1,71 @@ +package urllink + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/miniprogram/context" + "github.com/silenceper/wechat/v2/util" +) + +// URLLink 小程序 URL Link +type URLLink struct { + *context.Context +} + +// NewURLLink 实例化 +func NewURLLink(ctx *context.Context) *URLLink { + return &URLLink{Context: ctx} +} + +const generateURL = "https://api.weixin.qq.com/wxa/generate_urllink" + +// TExpireType 失效类型 (指定时间戳/指定间隔) +type TExpireType int + +const ( + // ExpireTypeTime 指定时间戳后失效 + ExpireTypeTime TExpireType = 0 + + // ExpireTypeInterval 间隔指定天数后失效 + ExpireTypeInterval TExpireType = 1 +) + +// ULParams 请求参数 +// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html#请求参数 +type ULParams struct { + Path string `json:"path"` + Query string `json:"query"` + IsExpire bool `json:"is_expire"` + ExpireType TExpireType `json:"expire_type"` + ExpireTime int64 `json:"expire_time"` + ExpireInterval int `json:"expire_interval"` +} + +// ULResult 返回的结果 +// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html#返回值 +type ULResult struct { + util.CommonError + + URLLink string `json:"url_link"` +} + +// Generate 生成url link +func (u *URLLink) Generate(params *ULParams) (string, error) { + var accessToken string + accessToken, err := u.GetAccessToken() + if err != nil { + return "", err + } + + uri := fmt.Sprintf("%s?access_token=%s", generateURL, accessToken) + response, err := util.PostJSON(uri, params) + if err != nil { + return "", err + } + var resp ULResult + err = util.DecodeWithError(response, &resp, "URLLink.Generate") + if err != nil { + return "", err + } + return resp.URLLink, nil +} From 39ed108b11e97592540b4a8d548dc224424f50ca Mon Sep 17 00:00:00 2001 From: youkjw <445142575@qq.com> Date: Tue, 7 Sep 2021 16:07:23 +0800 Subject: [PATCH 02/84] =?UTF-8?q?=E6=8E=A5=E5=85=A5=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E8=AE=A2=E5=8D=95=20(#471)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 接入关闭订单 * test * 删除testing,过不了ci * 避免err覆盖 Co-authored-by: liujianwei --- pay/order/close.go | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 pay/order/close.go diff --git a/pay/order/close.go b/pay/order/close.go new file mode 100644 index 0000000..b8976a5 --- /dev/null +++ b/pay/order/close.go @@ -0,0 +1,98 @@ +package order + +import ( + "encoding/xml" + "errors" + + "github.com/silenceper/wechat/v2/util" +) + +// https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3 +var closeGateway = "https://api.mch.weixin.qq.com/pay/closeorder" + +// CloseParams 传入的参数 +type CloseParams struct { + OutTradeNo string // 商户订单号 + SignType string // 签名类型 +} + +// closeRequest 接口请求参数 +type closeRequest struct { + AppID string `xml:"appid"` // 公众账号ID + MchID string `xml:"mch_id"` // 商户号 + NonceStr string `xml:"nonce_str"` // 随机字符串 + Sign string `xml:"sign"` // 签名 + SignType string `xml:"sign_type,omitempty"` // 签名类型 + OutTradeNo string `xml:"out_trade_no"` // 商户订单号 +} + +// CloseResult 关闭订单返回结果 +type CloseResult struct { + ReturnCode *string `xml:"return_code"` + ReturnMsg *string `xml:"return_msg"` + + AppID *string `xml:"appid" json:"appid"` + MchID *string `xml:"mch_id"` + NonceStr *string `xml:"nonce_str"` + Sign *string `xml:"sign"` + ResultCode *string `xml:"result_code"` + ResultMsg *string `xml:"result_msg"` + ErrCode *string `xml:"err_code"` + ErrCodeDes *string `xml:"err_code_des"` +} + +// CloseOrder 关闭订单 +func (o *Order) CloseOrder(p *CloseParams) (closeResult CloseResult, err error) { + nonceStr := util.RandomStr(32) + // 签名类型 + if p.SignType == "" { + p.SignType = "MD5" + } + + params := make(map[string]string) + params["appid"] = o.AppID + params["mch_id"] = o.MchID + params["nonce_str"] = nonceStr + params["out_trade_no"] = p.OutTradeNo + params["sign_type"] = p.SignType + + var ( + sign string + rawRet []byte + ) + + sign, err = util.ParamSign(params, o.Key) + if err != nil { + return + } + request := closeRequest{ + AppID: o.AppID, + MchID: o.MchID, + NonceStr: nonceStr, + Sign: sign, + OutTradeNo: p.OutTradeNo, + SignType: p.SignType, + } + + rawRet, err = util.PostXML(closeGateway, request) + if err != nil { + return + } + + err = xml.Unmarshal(rawRet, &closeResult) + if err != nil { + return + } + + if *closeResult.ReturnCode == SUCCESS { + // close success + if *closeResult.ResultCode == SUCCESS { + err = nil + return + } + err = errors.New(*closeResult.ErrCode + *closeResult.ErrCodeDes) + return + } + err = errors.New("[msg : xmlUnmarshalError] [rawReturn : " + string(rawRet) + "] [sign : " + sign + "]") + return +} From 47adf42208d0b13bd2b31bdba8b27afae59d15a6 Mon Sep 17 00:00:00 2001 From: George Wang Date: Wed, 8 Sep 2021 10:11:06 +0800 Subject: [PATCH 03/84] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E7=BC=BA=E5=B0=91notify=5Furl=E7=9A=84bug=20?= =?UTF-8?q?(#472)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pay/order/pay.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pay/order/pay.go b/pay/order/pay.go index 4dc7f87..3da2a08 100644 --- a/pay/order/pay.go +++ b/pay/order/pay.go @@ -210,6 +210,12 @@ func (o *Order) BridgeAppConfig(p *Params) (cfg ConfigForApp, err error) { // PrePayOrder return data for invoke wechat payment func (o *Order) PrePayOrder(p *Params) (payOrder PreOrder, err error) { nonceStr := util.RandomStr(32) + + // 通知地址 + if len(p.NotifyURL) == 0 { + p.NotifyURL = o.NotifyURL // 默认使用order.NotifyURL + } + param := map[string]string{ "appid": o.AppID, "body": p.Body, @@ -224,17 +230,13 @@ func (o *Order) PrePayOrder(p *Params) (payOrder PreOrder, err error) { "detail": p.Detail, "attach": p.Attach, "goods_tag": p.GoodsTag, + "notify_url": p.NotifyURL, } // 签名类型 if param["sign_type"] == "" { param["sign_type"] = util.SignTypeMD5 } - // 通知地址 - if p.NotifyURL != "" { - param["notify_url"] = p.NotifyURL - } - if p.TimeExpire != "" { // 如果有传入交易结束时间 param["time_expire"] = p.TimeExpire From 96c1f98944e451c707113508ce0eeb67c667b4dc Mon Sep 17 00:00:00 2001 From: houseme Date: Wed, 8 Sep 2021 11:03:23 +0800 Subject: [PATCH 04/84] =?UTF-8?q?[feature]=20Format=20the=20code=20and=20i?= =?UTF-8?q?mprove=20Mini=20Program=20authorization=20to=20o=E2=80=A6=20(#4?= =?UTF-8?q?73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feature] Format the code and improve Mini Program authorization to obtain openid(miniprogram/auth/auth.go Code2Session) * [feature] CheckEncryptedData (https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/user-info/auth.checkEncryptedData.html) * upgrade json error * upgrade json error Co-authored-by: houseme --- cache/memory.go | 10 +- cache/redis.go | 20 +- credential/access_token.go | 2 +- credential/default_access_token.go | 34 +-- credential/default_access_token_test.go | 1 + credential/default_js_ticket.go | 14 +- credential/js_ticket.go | 4 +- go.mod | 2 +- go.sum | 4 +- miniprogram/analysis/analysis.go | 4 +- miniprogram/auth/auth.go | 45 +++- miniprogram/config/config.go | 2 +- miniprogram/content/content.go | 14 +- miniprogram/encryptor/encryptor.go | 4 +- miniprogram/message/consts.go | 8 +- miniprogram/message/customer_message.go | 34 +-- miniprogram/miniprogram.go | 16 +- miniprogram/qrcode/qrcode.go | 4 +- miniprogram/subscribe/subscribe.go | 24 +-- miniprogram/tcb/cloudfunction.go | 8 +- miniprogram/tcb/database.go | 198 +++++++++--------- miniprogram/tcb/file.go | 48 ++--- miniprogram/tcb/tcb.go | 4 +- miniprogram/urllink/urllink.go | 1 - officialaccount/basic/basic.go | 18 +- officialaccount/broadcast/broadcast.go | 62 +++--- officialaccount/config/config.go | 10 +- officialaccount/datacube/broadcast.go | 26 +-- officialaccount/datacube/datacube.go | 4 +- officialaccount/datacube/interface.go | 8 +- officialaccount/datacube/message.go | 28 +-- officialaccount/datacube/publisher.go | 52 ++--- officialaccount/datacube/user.go | 8 +- officialaccount/device/authorize.go | 20 +- officialaccount/device/device.go | 4 +- officialaccount/device/message.go | 2 +- officialaccount/device/qrcode.go | 4 +- officialaccount/js/js.go | 8 +- officialaccount/material/material.go | 40 ++-- officialaccount/material/media.go | 22 +- officialaccount/menu/button.go | 50 ++--- officialaccount/menu/menu.go | 42 ++-- officialaccount/message/customer_message.go | 60 +++--- officialaccount/message/image.go | 4 +- officialaccount/message/message.go | 84 ++++---- officialaccount/message/music.go | 4 +- officialaccount/message/news.go | 8 +- officialaccount/message/reply.go | 6 +- officialaccount/message/subscribe.go | 26 +-- officialaccount/message/template.go | 18 +- officialaccount/message/text.go | 4 +- officialaccount/message/transfer_customer.go | 6 +- officialaccount/message/video.go | 4 +- officialaccount/message/voice.go | 4 +- officialaccount/oauth/oauth.go | 20 +- officialaccount/ocr/ocr.go | 40 ++-- officialaccount/officialaccount.go | 18 +- officialaccount/server/server.go | 36 ++-- officialaccount/server/util.go | 10 +- officialaccount/user/migrate.go | 6 +- officialaccount/user/tag.go | 18 +- officialaccount/user/user.go | 8 +- openplatform/account/account.go | 14 +- openplatform/config/config.go | 10 +- openplatform/context/accessToken.go | 10 +- openplatform/miniprogram/basic/basic.go | 16 +- .../miniprogram/component/component.go | 32 +-- openplatform/miniprogram/miniprogram.go | 10 +- openplatform/officialaccount/js/js.go | 8 +- openplatform/officialaccount/oauth/oauth.go | 6 +- .../officialaccount/officialaccount.go | 16 +- openplatform/openplatform.go | 14 +- pay/config/config.go | 2 +- pay/notify/notify.go | 4 +- pay/order/pay.go | 6 +- pay/pay.go | 4 +- pay/transfer/transfer_wallet.go | 10 +- util/crypto.go | 4 +- util/http.go | 20 +- util/signature.go | 2 +- util/signature_test.go | 2 +- util/string.go | 2 +- util/time.go | 2 +- util/util.go | 2 +- wechat.go | 4 +- work/kf/servicestate.go | 12 +- work/msgaudit/client_linux.go | 3 +- work/msgaudit/client_unsupport.go | 3 +- work/oauth/oauth.go | 26 +-- work/work.go | 6 +- 90 files changed, 787 insertions(+), 760 deletions(-) diff --git a/cache/memory.go b/cache/memory.go index 7206637..135d9d9 100644 --- a/cache/memory.go +++ b/cache/memory.go @@ -5,7 +5,7 @@ import ( "time" ) -//Memory struct contains *memcache.Client +// Memory struct contains *memcache.Client type Memory struct { sync.Mutex @@ -17,14 +17,14 @@ type data struct { Expired time.Time } -//NewMemory create new memcache +// NewMemory create new memcache func NewMemory() *Memory { return &Memory{ data: map[string]*data{}, } } -//Get return cached value +// Get return cached value func (mem *Memory) Get(key string) interface{} { if ret, ok := mem.data[key]; ok { if ret.Expired.Before(time.Now()) { @@ -48,7 +48,7 @@ func (mem *Memory) IsExist(key string) bool { return false } -//Set cached value with key and expire time. +// Set cached value with key and expire time. func (mem *Memory) Set(key string, val interface{}, timeout time.Duration) (err error) { mem.Lock() defer mem.Unlock() @@ -60,7 +60,7 @@ func (mem *Memory) Set(key string, val interface{}, timeout time.Duration) (err return nil } -//Delete delete value in memcache. +// Delete delete value in memcache. func (mem *Memory) Delete(key string) error { mem.deleteKey(key) return nil diff --git a/cache/redis.go b/cache/redis.go index e314739..f685e6a 100644 --- a/cache/redis.go +++ b/cache/redis.go @@ -7,22 +7,22 @@ import ( "github.com/gomodule/redigo/redis" ) -//Redis redis cache +// Redis .redis cache type Redis struct { conn *redis.Pool } -//RedisOpts redis 连接属性 +// RedisOpts redis 连接属性 type RedisOpts struct { Host string `yml:"host" json:"host"` Password string `yml:"password" json:"password"` Database int `yml:"database" json:"database"` MaxIdle int `yml:"max_idle" json:"max_idle"` MaxActive int `yml:"max_active" json:"max_active"` - IdleTimeout int `yml:"idle_timeout" json:"idle_timeout"` //second + IdleTimeout int `yml:"idle_timeout" json:"idle_timeout"` // second } -//NewRedis 实例化 +// NewRedis 实例化 func NewRedis(opts *RedisOpts) *Redis { pool := &redis.Pool{ MaxActive: opts.MaxActive, @@ -45,17 +45,17 @@ func NewRedis(opts *RedisOpts) *Redis { return &Redis{pool} } -//SetRedisPool 设置redis连接池 +// SetRedisPool 设置redis连接池 func (r *Redis) SetRedisPool(pool *redis.Pool) { r.conn = pool } -//SetConn 设置conn +// SetConn 设置conn func (r *Redis) SetConn(conn *redis.Pool) { r.conn = conn } -//Get 获取一个值 +// Get 获取一个值 func (r *Redis) Get(key string) interface{} { conn := r.conn.Get() defer conn.Close() @@ -73,7 +73,7 @@ func (r *Redis) Get(key string) interface{} { return reply } -//Set 设置一个值 +// Set 设置一个值 func (r *Redis) Set(key string, val interface{}, timeout time.Duration) (err error) { conn := r.conn.Get() defer conn.Close() @@ -88,7 +88,7 @@ func (r *Redis) Set(key string, val interface{}, timeout time.Duration) (err err return } -//IsExist 判断key是否存在 +// IsExist 判断key是否存在 func (r *Redis) IsExist(key string) bool { conn := r.conn.Get() defer conn.Close() @@ -98,7 +98,7 @@ func (r *Redis) IsExist(key string) bool { return i > 0 } -//Delete 删除 +// Delete 删除 func (r *Redis) Delete(key string) error { conn := r.conn.Get() defer conn.Close() diff --git a/credential/access_token.go b/credential/access_token.go index 362e705..fcc4668 100644 --- a/credential/access_token.go +++ b/credential/access_token.go @@ -1,6 +1,6 @@ package credential -//AccessTokenHandle AccessToken 接口 +// AccessTokenHandle AccessToken 接口 type AccessTokenHandle interface { GetAccessToken() (accessToken string, err error) } diff --git a/credential/default_access_token.go b/credential/default_access_token.go index 1c360c2..7c91544 100644 --- a/credential/default_access_token.go +++ b/credential/default_access_token.go @@ -11,19 +11,19 @@ import ( ) const ( - //AccessTokenURL 获取access_token的接口 + // AccessTokenURL 获取access_token的接口 accessTokenURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s" - //AccessTokenURL 企业微信获取access_token的接口 + // AccessTokenURL 企业微信获取access_token的接口 workAccessTokenURL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s" - //CacheKeyOfficialAccountPrefix 微信公众号cache key前缀 + // CacheKeyOfficialAccountPrefix 微信公众号cache key前缀 CacheKeyOfficialAccountPrefix = "gowechat_officialaccount_" - //CacheKeyMiniProgramPrefix 小程序cache key前缀 + // CacheKeyMiniProgramPrefix 小程序cache key前缀 CacheKeyMiniProgramPrefix = "gowechat_miniprogram_" - //CacheKeyWorkPrefix 企业微信cache key前缀 + // CacheKeyWorkPrefix 企业微信cache key前缀 CacheKeyWorkPrefix = "gowechat_work_" ) -//DefaultAccessToken 默认AccessToken 获取 +// DefaultAccessToken 默认AccessToken 获取 type DefaultAccessToken struct { appID string appSecret string @@ -32,7 +32,7 @@ type DefaultAccessToken struct { accessTokenLock *sync.Mutex } -//NewDefaultAccessToken new DefaultAccessToken +// NewDefaultAccessToken new DefaultAccessToken func NewDefaultAccessToken(appID, appSecret, cacheKeyPrefix string, cache cache.Cache) AccessTokenHandle { if cache == nil { panic("cache is ineed") @@ -46,7 +46,7 @@ func NewDefaultAccessToken(appID, appSecret, cacheKeyPrefix string, cache cache. } } -//ResAccessToken struct +// ResAccessToken struct type ResAccessToken struct { util.CommonError @@ -54,7 +54,7 @@ type ResAccessToken struct { ExpiresIn int64 `json:"expires_in"` } -//GetAccessToken 获取access_token,先从cache中获取,没有则从服务端获取 +// GetAccessToken 获取access_token,先从cache中获取,没有则从服务端获取 func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) { // 先从cache中取 accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", ak.cacheKeyPrefix, ak.appID) @@ -62,7 +62,7 @@ func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) { return val.(string), nil } - //加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token + // 加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token ak.accessTokenLock.Lock() defer ak.accessTokenLock.Unlock() @@ -71,7 +71,7 @@ func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) { return val.(string), nil } - //cache失效,从微信服务器获取 + // cache失效,从微信服务器获取 var resAccessToken ResAccessToken resAccessToken, err = GetTokenFromServer(fmt.Sprintf(accessTokenURL, ak.appID, ak.appSecret)) if err != nil { @@ -87,7 +87,7 @@ func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) { return } -//WorkAccessToken 企业微信AccessToken 获取 +// WorkAccessToken 企业微信AccessToken 获取 type WorkAccessToken struct { CorpID string CorpSecret string @@ -96,7 +96,7 @@ type WorkAccessToken struct { accessTokenLock *sync.Mutex } -//NewWorkAccessToken new WorkAccessToken +// NewWorkAccessToken new WorkAccessToken func NewWorkAccessToken(corpID, corpSecret, cacheKeyPrefix string, cache cache.Cache) AccessTokenHandle { if cache == nil { panic("cache the not exist") @@ -110,9 +110,9 @@ func NewWorkAccessToken(corpID, corpSecret, cacheKeyPrefix string, cache cache.C } } -//GetAccessToken 企业微信获取access_token,先从cache中获取,没有则从服务端获取 +// GetAccessToken 企业微信获取access_token,先从cache中获取,没有则从服务端获取 func (ak *WorkAccessToken) GetAccessToken() (accessToken string, err error) { - //加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token + // 加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token ak.accessTokenLock.Lock() defer ak.accessTokenLock.Unlock() accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", ak.cacheKeyPrefix, ak.CorpID) @@ -122,7 +122,7 @@ func (ak *WorkAccessToken) GetAccessToken() (accessToken string, err error) { return } - //cache失效,从微信服务器获取 + // cache失效,从微信服务器获取 var resAccessToken ResAccessToken resAccessToken, err = GetTokenFromServer(fmt.Sprintf(workAccessTokenURL, ak.CorpID, ak.CorpSecret)) if err != nil { @@ -138,7 +138,7 @@ func (ak *WorkAccessToken) GetAccessToken() (accessToken string, err error) { return } -//GetTokenFromServer 强制从微信服务器获取token +// GetTokenFromServer 强制从微信服务器获取token func GetTokenFromServer(url string) (resAccessToken ResAccessToken, err error) { var body []byte body, err = util.HTTPGet(url) diff --git a/credential/default_access_token_test.go b/credential/default_access_token_test.go index feafe39..93e4ee6 100644 --- a/credential/default_access_token_test.go +++ b/credential/default_access_token_test.go @@ -7,6 +7,7 @@ import ( "gopkg.in/h2non/gock.v1" ) +// TestGetTicketFromServer . func TestGetTicketFromServer(t *testing.T) { defer gock.Off() gock.New(getTicketURL).Reply(200).JSON(&ResTicket{Ticket: "mock-ticket", ExpiresIn: 10}) diff --git a/credential/default_js_ticket.go b/credential/default_js_ticket.go index 369d13d..5ba55c3 100644 --- a/credential/default_js_ticket.go +++ b/credential/default_js_ticket.go @@ -10,19 +10,19 @@ import ( "github.com/silenceper/wechat/v2/util" ) -//获取ticket的url +// getTicketURL 获取ticket的url const getTicketURL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi" -//DefaultJsTicket 默认获取js ticket方法 +// DefaultJsTicket 默认获取js ticket方法 type DefaultJsTicket struct { appID string cacheKeyPrefix string cache cache.Cache - //jsAPITicket 读写锁 同一个AppID一个 + // jsAPITicket 读写锁 同一个AppID一个 jsAPITicketLock *sync.Mutex } -//NewDefaultJsTicket new +// NewDefaultJsTicket new func NewDefaultJsTicket(appID string, cacheKeyPrefix string, cache cache.Cache) JsTicketHandle { return &DefaultJsTicket{ appID: appID, @@ -40,9 +40,9 @@ type ResTicket struct { ExpiresIn int64 `json:"expires_in"` } -//GetTicket 获取jsapi_ticket +// GetTicket 获取jsapi_ticket func (js *DefaultJsTicket) GetTicket(accessToken string) (ticketStr string, err error) { - //先从cache中取 + // 先从cache中取 jsAPITicketCacheKey := fmt.Sprintf("%s_jsapi_ticket_%s", js.cacheKeyPrefix, js.appID) if val := js.cache.Get(jsAPITicketCacheKey); val != nil { return val.(string), nil @@ -67,7 +67,7 @@ func (js *DefaultJsTicket) GetTicket(accessToken string) (ticketStr string, err return } -//GetTicketFromServer 从服务器中获取ticket +// GetTicketFromServer 从服务器中获取ticket func GetTicketFromServer(accessToken string) (ticket ResTicket, err error) { var response []byte url := fmt.Sprintf(getTicketURL, accessToken) diff --git a/credential/js_ticket.go b/credential/js_ticket.go index e6f4ebc..d2f3c0c 100644 --- a/credential/js_ticket.go +++ b/credential/js_ticket.go @@ -1,7 +1,7 @@ package credential -//JsTicketHandle js ticket获取 +// JsTicketHandle js ticket获取 type JsTicketHandle interface { - //GetTicket 获取ticket + // GetTicket 获取ticket GetTicket(accessToken string) (ticket string, err error) } diff --git a/go.mod b/go.mod index a019377..cce929f 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b github.com/fatih/structs v1.1.0 - github.com/gomodule/redigo v1.8.4 + github.com/gomodule/redigo v1.8.5 github.com/kr/text v0.2.0 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/sirupsen/logrus v1.8.1 diff --git a/go.sum b/go.sum index 08e4cc6..281570b 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/gomodule/redigo v1.8.4 h1:Z5JUg94HMTR1XpwBaSH4vq3+PNSIykBLxMdglbw10gg= -github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc= +github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= diff --git a/miniprogram/analysis/analysis.go b/miniprogram/analysis/analysis.go index d3ca02c..dae278b 100644 --- a/miniprogram/analysis/analysis.go +++ b/miniprogram/analysis/analysis.go @@ -32,12 +32,12 @@ const ( getAnalysisVisitPageURL = "https://api.weixin.qq.com/datacube/getweanalysisappidvisitpage?access_token=%s" ) -//Analysis analyis 数据分析 +// Analysis analyis 数据分析 type Analysis struct { *context.Context } -//NewAnalysis new +// NewAnalysis new func NewAnalysis(ctx *context.Context) *Analysis { return &Analysis{ctx} } diff --git a/miniprogram/auth/auth.go b/miniprogram/auth/auth.go index 377e2b7..4f239f7 100644 --- a/miniprogram/auth/auth.go +++ b/miniprogram/auth/auth.go @@ -10,14 +10,16 @@ import ( const ( code2SessionURL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code" + + checkEncryptedDataURL = "https://api.weixin.qq.com/wxa/business/checkencryptedmsg?access_token=%s" ) -//Auth 登录/用户信息 +// Auth 登录/用户信息 type Auth struct { *context.Context } -//NewAuth new auth +// NewAuth new auth func NewAuth(ctx *context.Context) *Auth { return &Auth{ctx} } @@ -31,16 +33,21 @@ type ResCode2Session struct { UnionID string `json:"unionid"` // 用户在开放平台的唯一标识符,在满足UnionID下发条件的情况下会返回 } -//Code2Session 登录凭证校验。 +// RspCheckEncryptedData . +type RspCheckEncryptedData struct { + util.CommonError + + Vaild bool `json:"vaild"` // 是否是合法的数据 + CreateTime uint `json:"create_time"` // 加密数据生成的时间戳 +} + +// Code2Session 登录凭证校验。 func (auth *Auth) Code2Session(jsCode string) (result ResCode2Session, err error) { - urlStr := fmt.Sprintf(code2SessionURL, auth.AppID, auth.AppSecret, jsCode) var response []byte - response, err = util.HTTPGet(urlStr) - if err != nil { + if response, err = util.HTTPGet(fmt.Sprintf(code2SessionURL, auth.AppID, auth.AppSecret, jsCode)); err != nil { return } - err = json.Unmarshal(response, &result) - if err != nil { + if err = json.Unmarshal(response, &result); err != nil { return } if result.ErrCode != 0 { @@ -50,7 +57,25 @@ func (auth *Auth) Code2Session(jsCode string) (result ResCode2Session, err error return } -//GetPaidUnionID 用户支付完成后,获取该用户的 UnionId,无需用户授权 +// GetPaidUnionID 用户支付完成后,获取该用户的 UnionId,无需用户授权 func (auth *Auth) GetPaidUnionID() { - //TODO + // TODO +} + +// CheckEncryptedData .检查加密信息是否由微信生成(当前只支持手机号加密数据),只能检测最近3天生成的加密数据 +func (auth *Auth) CheckEncryptedData(encryptedMsgHash string) (result RspCheckEncryptedData, err error) { + var response []byte + var ( + at string + ) + if at, err = auth.GetAccessToken(); err != nil { + return + } + if response, err = util.HTTPPost(fmt.Sprintf(checkEncryptedDataURL, at), "encrypted_msg_hash="+encryptedMsgHash); err != nil { + return + } + if err = util.DecodeWithError(response, &result, "CheckEncryptedDataAuth"); err != nil { + return + } + return } diff --git a/miniprogram/config/config.go b/miniprogram/config/config.go index b121443..c2d888e 100644 --- a/miniprogram/config/config.go +++ b/miniprogram/config/config.go @@ -5,7 +5,7 @@ import ( "github.com/silenceper/wechat/v2/cache" ) -// Config config for 小程序 +// Config .config for 小程序 type Config struct { AppID string `json:"app_id"` // appid AppSecret string `json:"app_secret"` // appsecret diff --git a/miniprogram/content/content.go b/miniprogram/content/content.go index 86ab46c..91f6921 100644 --- a/miniprogram/content/content.go +++ b/miniprogram/content/content.go @@ -12,18 +12,18 @@ const ( checkImageURL = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=%s" ) -//Content 内容安全 +// Content 内容安全 type Content struct { *context.Context } -//NewContent 内容安全接口 +// NewContent 内容安全接口 func NewContent(ctx *context.Context) *Content { return &Content{ctx} } -//CheckText 检测文字 -//@text 需要检测的文字 +// CheckText 检测文字 +// @text 需要检测的文字 func (content *Content) CheckText(text string) error { accessToken, err := content.GetAccessToken() if err != nil { @@ -41,9 +41,9 @@ func (content *Content) CheckText(text string) error { return util.DecodeWithCommonError(response, "ContentCheckText") } -//CheckImage 检测图片 -//所传参数为要检测的图片文件的绝对路径,图片格式支持PNG、JPEG、JPG、GIF, 像素不超过 750 x 1334,同时文件大小以不超过 300K 为宜,否则可能报错 -//@media 图片文件的绝对路径 +// CheckImage 检测图片 +// 所传参数为要检测的图片文件的绝对路径,图片格式支持PNG、JPEG、JPG、GIF, 像素不超过 750 x 1334,同时文件大小以不超过 300K 为宜,否则可能报错 +// @media 图片文件的绝对路径 func (content *Content) CheckImage(media string) error { accessToken, err := content.GetAccessToken() if err != nil { diff --git a/miniprogram/encryptor/encryptor.go b/miniprogram/encryptor/encryptor.go index bd8613f..26a57a5 100644 --- a/miniprogram/encryptor/encryptor.go +++ b/miniprogram/encryptor/encryptor.go @@ -10,12 +10,12 @@ import ( "github.com/silenceper/wechat/v2/miniprogram/context" ) -//Encryptor struct +// Encryptor struct type Encryptor struct { *context.Context } -//NewEncryptor 实例 +// NewEncryptor 实例 func NewEncryptor(context *context.Context) *Encryptor { basic := new(Encryptor) basic.Context = context diff --git a/miniprogram/message/consts.go b/miniprogram/message/consts.go index 444a26a..cd8f585 100644 --- a/miniprogram/message/consts.go +++ b/miniprogram/message/consts.go @@ -12,13 +12,13 @@ type EventType string type InfoType string const ( - //MsgTypeText 文本消息 + // MsgTypeText 文本消息 MsgTypeText MsgType = "text" - //MsgTypeImage 图片消息 + // MsgTypeImage 图片消息 MsgTypeImage = "image" - //MsgTypeLink 图文链接 + // MsgTypeLink 图文链接 MsgTypeLink = "link" - //MsgTypeMiniProgramPage 小程序卡片 + // MsgTypeMiniProgramPage 小程序卡片 MsgTypeMiniProgramPage = "miniprogrampage" ) diff --git a/miniprogram/message/customer_message.go b/miniprogram/message/customer_message.go index fe650d0..ce3830f 100644 --- a/miniprogram/message/customer_message.go +++ b/miniprogram/message/customer_message.go @@ -11,29 +11,29 @@ const ( customerSendMessage = "https://api.weixin.qq.com/cgi-bin/message/custom/send" ) -//Manager 消息管理者,可以发送消息 +// Manager 消息管理者,可以发送消息 type Manager struct { *context.Context } -//NewCustomerMessageManager 实例化消息管理者 +// NewCustomerMessageManager 实例化消息管理者 func NewCustomerMessageManager(context *context.Context) *Manager { return &Manager{ context, } } -//MediaText 文本消息的文字 +// MediaText 文本消息的文字 type MediaText struct { Content string `json:"content"` } -//MediaResource 消息使用的临时素材id +// MediaResource 消息使用的临时素材id type MediaResource struct { MediaID string `json:"media_id"` } -//MediaMiniprogrampage 小程序卡片 +// MediaMiniprogrampage 小程序卡片 type MediaMiniprogrampage struct { Title string `json:"title"` Appid string `json:"appid"` @@ -49,17 +49,17 @@ type MediaLink struct { ThumbURL string `json:"thumb_url"` } -//CustomerMessage 客服消息 +// CustomerMessage 客服消息 type CustomerMessage struct { - ToUser string `json:"touser"` //接受者OpenID - Msgtype MsgType `json:"msgtype"` //客服消息类型 - Text *MediaText `json:"text,omitempty"` //可选 - Image *MediaResource `json:"image,omitempty"` //可选 - Link *MediaLink `json:"link,omitempty"` //可选 - Miniprogrampage *MediaMiniprogrampage `json:"miniprogrampage,omitempty"` //可选 + ToUser string `json:"touser"` // 接受者OpenID + Msgtype MsgType `json:"msgtype"` // 客服消息类型 + Text *MediaText `json:"text,omitempty"` // 可选 + Image *MediaResource `json:"image,omitempty"` // 可选 + Link *MediaLink `json:"link,omitempty"` // 可选 + Miniprogrampage *MediaMiniprogrampage `json:"miniprogrampage,omitempty"` // 可选 } -//NewCustomerTextMessage 文本消息结构体构造方法 +// NewCustomerTextMessage 文本消息结构体构造方法 func NewCustomerTextMessage(toUser, text string) *CustomerMessage { return &CustomerMessage{ ToUser: toUser, @@ -70,7 +70,7 @@ func NewCustomerTextMessage(toUser, text string) *CustomerMessage { } } -//NewCustomerImgMessage 图片消息的构造方法 +// NewCustomerImgMessage 图片消息的构造方法 func NewCustomerImgMessage(toUser, mediaID string) *CustomerMessage { return &CustomerMessage{ ToUser: toUser, @@ -81,7 +81,7 @@ func NewCustomerImgMessage(toUser, mediaID string) *CustomerMessage { } } -//NewCustomerLinkMessage 图文链接消息的构造方法 +// NewCustomerLinkMessage 图文链接消息的构造方法 func NewCustomerLinkMessage(toUser, title, description, url, thumbURL string) *CustomerMessage { return &CustomerMessage{ ToUser: toUser, @@ -95,7 +95,7 @@ func NewCustomerLinkMessage(toUser, title, description, url, thumbURL string) *C } } -//NewCustomerMiniprogrampageMessage 小程序卡片消息的构造方法 +// NewCustomerMiniprogrampageMessage 小程序卡片消息的构造方法 func NewCustomerMiniprogrampageMessage(toUser, title, pagepath, thumbMediaID string) *CustomerMessage { return &CustomerMessage{ ToUser: toUser, @@ -108,7 +108,7 @@ func NewCustomerMiniprogrampageMessage(toUser, title, pagepath, thumbMediaID str } } -//Send 发送客服消息 +// Send 发送客服消息 func (manager *Manager) Send(msg *CustomerMessage) error { accessToken, err := manager.Context.GetAccessToken() if err != nil { diff --git a/miniprogram/miniprogram.go b/miniprogram/miniprogram.go index ab32996..4ebbe09 100644 --- a/miniprogram/miniprogram.go +++ b/miniprogram/miniprogram.go @@ -17,12 +17,12 @@ import ( "github.com/silenceper/wechat/v2/miniprogram/werun" ) -//MiniProgram 微信小程序相关API +// MiniProgram 微信小程序相关API type MiniProgram struct { ctx *context.Context } -//NewMiniProgram 实例化小程序API +// NewMiniProgram 实例化小程序API func NewMiniProgram(cfg *config.Config) *MiniProgram { defaultAkHandle := credential.NewDefaultAccessToken(cfg.AppID, cfg.AppSecret, credential.CacheKeyMiniProgramPrefix, cfg.Cache) ctx := &context.Context{ @@ -32,7 +32,7 @@ func NewMiniProgram(cfg *config.Config) *MiniProgram { return &MiniProgram{ctx} } -//SetAccessTokenHandle 自定义access_token获取方式 +// SetAccessTokenHandle 自定义access_token获取方式 func (miniProgram *MiniProgram) SetAccessTokenHandle(accessTokenHandle credential.AccessTokenHandle) { miniProgram.ctx.AccessTokenHandle = accessTokenHandle } @@ -47,27 +47,27 @@ func (miniProgram *MiniProgram) GetEncryptor() *encryptor.Encryptor { return encryptor.NewEncryptor(miniProgram.ctx) } -//GetAuth 登录/用户信息相关接口 +// GetAuth 登录/用户信息相关接口 func (miniProgram *MiniProgram) GetAuth() *auth.Auth { return auth.NewAuth(miniProgram.ctx) } -//GetAnalysis 数据分析 +// GetAnalysis 数据分析 func (miniProgram *MiniProgram) GetAnalysis() *analysis.Analysis { return analysis.NewAnalysis(miniProgram.ctx) } -//GetQRCode 小程序码相关API +// GetQRCode 小程序码相关API func (miniProgram *MiniProgram) GetQRCode() *qrcode.QRCode { return qrcode.NewQRCode(miniProgram.ctx) } -//GetTcb 小程序云开发API +// GetTcb 小程序云开发API func (miniProgram *MiniProgram) GetTcb() *tcb.Tcb { return tcb.NewTcb(miniProgram.ctx) } -//GetSubscribe 小程序订阅消息 +// GetSubscribe 小程序订阅消息 func (miniProgram *MiniProgram) GetSubscribe() *subscribe.Subscribe { return subscribe.NewSubscribe(miniProgram.ctx) } diff --git a/miniprogram/qrcode/qrcode.go b/miniprogram/qrcode/qrcode.go index 26e3db7..3ee3179 100644 --- a/miniprogram/qrcode/qrcode.go +++ b/miniprogram/qrcode/qrcode.go @@ -15,12 +15,12 @@ const ( getWXACodeUnlimitURL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s" ) -//QRCode struct +// QRCode struct type QRCode struct { *context.Context } -//NewQRCode 实例 +// NewQRCode 实例 func NewQRCode(context *context.Context) *QRCode { qrCode := new(QRCode) qrCode.Context = context diff --git a/miniprogram/subscribe/subscribe.go b/miniprogram/subscribe/subscribe.go index dad44b8..0015a43 100644 --- a/miniprogram/subscribe/subscribe.go +++ b/miniprogram/subscribe/subscribe.go @@ -8,8 +8,8 @@ import ( ) const ( - //发送订阅消息 - //https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html + // 发送订阅消息 + // 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" // 获取当前帐号下的个人模板列表 @@ -41,21 +41,21 @@ func NewSubscribe(ctx *context.Context) *Subscribe { // 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 + 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 的值 +// DataItem 模版内某个 .DATA 的值 type DataItem struct { Value interface{} `json:"value"` Color string `json:"color"` } -//TemplateItem template item +// TemplateItem template item type TemplateItem struct { PriTmplID string `json:"priTmplId"` Title string `json:"title"` @@ -64,7 +64,7 @@ type TemplateItem struct { Type int64 `json:"type"` } -//TemplateList template list +// TemplateList template list type TemplateList struct { util.CommonError Data []TemplateItem `json:"data"` @@ -85,7 +85,7 @@ func (s *Subscribe) Send(msg *Message) (err error) { return util.DecodeWithCommonError(response, "Send") } -//ListTemplates 获取当前帐号下的个人模板列表 +// 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() diff --git a/miniprogram/tcb/cloudfunction.go b/miniprogram/tcb/cloudfunction.go index 87b11ab..4fd40a9 100644 --- a/miniprogram/tcb/cloudfunction.go +++ b/miniprogram/tcb/cloudfunction.go @@ -7,17 +7,17 @@ import ( ) const ( - //触发云函数 + // 触发云函数 invokeCloudFunctionURL = "https://api.weixin.qq.com/tcb/invokecloudfunction" ) -//InvokeCloudFunctionRes 云函数调用返回结果 +// InvokeCloudFunctionRes 云函数调用返回结果 type InvokeCloudFunctionRes struct { util.CommonError - RespData string `json:"resp_data"` //云函数返回的buffer + RespData string `json:"resp_data"` // 云函数返回的buffer } -//InvokeCloudFunction 云函数调用 +// InvokeCloudFunction 云函数调用 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/functions/invokeCloudFunction.html func (tcb *Tcb) InvokeCloudFunction(env, name, args string) (*InvokeCloudFunctionRes, error) { accessToken, err := tcb.GetAccessToken() diff --git a/miniprogram/tcb/database.go b/miniprogram/tcb/database.go index 9d473dd..002e87c 100644 --- a/miniprogram/tcb/database.go +++ b/miniprogram/tcb/database.go @@ -7,191 +7,191 @@ import ( ) const ( - //数据库导入 + // 数据库导入 databaseMigrateImportURL = "https://api.weixin.qq.com/tcb/databasemigrateimport" - //数据库导出 + // 数据库导出 databaseMigrateExportURL = "https://api.weixin.qq.com/tcb/databasemigrateexport" - //数据库迁移状态查询 + // 数据库迁移状态查询 databaseMigrateQueryInfoURL = "https://api.weixin.qq.com/tcb/databasemigratequeryinfo" - //变更数据库索引 + // 变更数据库索引 updateIndexURL = "https://api.weixin.qq.com/tcb/updateindex" - //新增集合 + // 新增集合 databaseCollectionAddURL = "https://api.weixin.qq.com/tcb/databasecollectionadd" - //删除集合 + // 删除集合 databaseCollectionDeleteURL = "https://api.weixin.qq.com/tcb/databasecollectiondelete" - //获取特定云环境下集合信息 + // 获取特定云环境下集合信息 databaseCollectionGetURL = "https://api.weixin.qq.com/tcb/databasecollectionget" - //数据库插入记录 + // 数据库插入记录 databaseAddURL = "https://api.weixin.qq.com/tcb/databaseadd" - //数据库删除记录 + // 数据库删除记录 databaseDeleteURL = "https://api.weixin.qq.com/tcb/databasedelete" - //数据库更新记录 + // 数据库更新记录 databaseUpdateURL = "https://api.weixin.qq.com/tcb/databaseupdate" - //数据库查询记录 + // 数据库查询记录 databaseQueryURL = "https://api.weixin.qq.com/tcb/databasequery" - //统计集合记录数或统计查询语句对应的结果记录数 + // 统计集合记录数或统计查询语句对应的结果记录数 databaseCountURL = "https://api.weixin.qq.com/tcb/databasecount" - //ConflictModeInster 冲突处理模式 插入 + // ConflictModeInster 冲突处理模式 插入 ConflictModeInster ConflictMode = 1 - //ConflictModeUpsert 冲突处理模式 更新 + // ConflictModeUpsert 冲突处理模式 更新 ConflictModeUpsert ConflictMode = 2 - //FileTypeJSON 的合法值 json + // FileTypeJSON 的合法值 json FileTypeJSON FileType = 1 - //FileTypeCsv 的合法值 csv + // FileTypeCsv 的合法值 csv FileTypeCsv FileType = 2 ) -//ConflictMode 冲突处理模式 +// ConflictMode 冲突处理模式 type ConflictMode int -//FileType 文件上传和导出的允许文件类型 +// FileType 文件上传和导出的允许文件类型 type FileType int -//ValidDirections 合法的direction值 +// ValidDirections 合法的direction值 var ValidDirections = []string{"1", "-1", "2dsphere"} -//DatabaseMigrateExportReq 数据库出 请求参数 +// DatabaseMigrateExportReq 数据库出 请求参数 type DatabaseMigrateExportReq struct { - Env string `json:"env,omitempty"` //云环境ID - FilePath string `json:"file_path,omitempty"` //导出文件路径(导入文件需先上传到同环境的存储中,可使用开发者工具或 HTTP API的上传文件 API上传) - FileType FileType `json:"file_type,omitempty"` //导出文件类型,文件格式参考数据库导入指引中的文件格式部分 1:json 2:csv - Query string `json:"query,omitempty"` //导出条件 + Env string `json:"env,omitempty"` // 云环境ID + FilePath string `json:"file_path,omitempty"` // 导出文件路径(导入文件需先上传到同环境的存储中,可使用开发者工具或 HTTP API的上传文件 API上传) + FileType FileType `json:"file_type,omitempty"` // 导出文件类型,文件格式参考数据库导入指引中的文件格式部分 1:json 2:csv + Query string `json:"query,omitempty"` // 导出条件 } -//DatabaseMigrateExportRes 数据库导出 返回结果 +// DatabaseMigrateExportRes 数据库导出 返回结果 type DatabaseMigrateExportRes struct { util.CommonError - JobID int64 `json:"job_id"` //导出任务ID,可使用数据库迁移进度查询 API 查询导入进度及结果 + JobID int64 `json:"job_id"` // 导出任务ID,可使用数据库迁移进度查询 API 查询导入进度及结果 } -//DatabaseMigrateImportReq 数据库导入 请求参数 +// DatabaseMigrateImportReq 数据库导入 请求参数 type DatabaseMigrateImportReq struct { - Env string `json:"env,omitempty"` //云环境ID - CollectionName string `json:"collection_name,omitempty"` //集合名称 - FilePath string `json:"file_path,omitempty"` //导出文件路径(文件会导出到同环境的云存储中,可使用获取下载链接 API 获取下载链接) - FileType FileType `json:"file_type,omitempty"` //导入文件类型,文件格式参考数据库导入指引中的文件格式部分 1:json 2:csv - StopOnError bool `json:"stop_on_error,omitempty"` //是否在遇到错误时停止导入 - ConflictMode ConflictMode `json:"conflict_mode,omitempty"` //冲突处理模式 1:inster 2:UPSERT + Env string `json:"env,omitempty"` // 云环境ID + CollectionName string `json:"collection_name,omitempty"` // 集合名称 + FilePath string `json:"file_path,omitempty"` // 导出文件路径(文件会导出到同环境的云存储中,可使用获取下载链接 API 获取下载链接) + FileType FileType `json:"file_type,omitempty"` // 导入文件类型,文件格式参考数据库导入指引中的文件格式部分 1:json 2:csv + StopOnError bool `json:"stop_on_error,omitempty"` // 是否在遇到错误时停止导入 + ConflictMode ConflictMode `json:"conflict_mode,omitempty"` // 冲突处理模式 1:inster 2:UPSERT } -//DatabaseMigrateImportRes 数据库导入 返回结果 +// DatabaseMigrateImportRes 数据库导入 返回结果 type DatabaseMigrateImportRes struct { util.CommonError - JobID int64 `json:"job_id"` //导入任务ID,可使用数据库迁移进度查询 API 查询导入进度及结果 + JobID int64 `json:"job_id"` // 导入任务ID,可使用数据库迁移进度查询 API 查询导入进度及结果 } -//DatabaseMigrateQueryInfoRes 数据库迁移状态查询 +// DatabaseMigrateQueryInfoRes 数据库迁移状态查询 type DatabaseMigrateQueryInfoRes struct { util.CommonError - Status string `json:"status"` //导出状态 - RecordSuccess int64 `json:"record_success"` //导出成功记录数 - RecordFail int64 `json:"record_fail"` //导出失败记录数 - ErrMsg string `json:"err_msg"` //导出错误信息 - FileURL string `json:"file_url"` //导出文件下载地址 + Status string `json:"status"` // 导出状态 + RecordSuccess int64 `json:"record_success"` // 导出成功记录数 + RecordFail int64 `json:"record_fail"` // 导出失败记录数 + ErrMsg string `json:"err_msg"` // 导出错误信息 + FileURL string `json:"file_url"` // 导出文件下载地址 } -//UpdateIndexReq 变更数据库索引 请求参数 +// UpdateIndexReq 变更数据库索引 请求参数 type UpdateIndexReq struct { - Env string `json:"env,omitempty"` //云环境ID - CollectionName string `json:"collection_name,omitempty"` //集合名称 - CreateIndexes []CreateIndex `json:"create_indexes,omitempty"` //新增索引 - DropIndexes []DropIndex `json:"drop_indexes,omitempty"` //删除索引 + Env string `json:"env,omitempty"` // 云环境ID + CollectionName string `json:"collection_name,omitempty"` // 集合名称 + CreateIndexes []CreateIndex `json:"create_indexes,omitempty"` // 新增索引 + DropIndexes []DropIndex `json:"drop_indexes,omitempty"` // 删除索引 } -//CreateIndex 新增索引 +// CreateIndex 新增索引 type CreateIndex struct { - Name string `json:"name,omitempty"` //索引名 - Unique bool `json:"unique,omitempty"` //是否唯一 - Keys []CreateIndexKey `json:"keys,omitempty"` //索引字段 + Name string `json:"name,omitempty"` // 索引名 + Unique bool `json:"unique,omitempty"` // 是否唯一 + Keys []CreateIndexKey `json:"keys,omitempty"` // 索引字段 } -//CreateIndexKey create index key +// CreateIndexKey create index key type CreateIndexKey struct { - Name string `json:"name,omitempty"` //字段名 - Direction string `json:"direction,omitempty"` //字段排序 + Name string `json:"name,omitempty"` // 字段名 + Direction string `json:"direction,omitempty"` // 字段排序 } -//DropIndex 删除索引 +// DropIndex 删除索引 type DropIndex struct { Name string `json:"name,omitempty"` } -//DatabaseCollectionReq 新增/删除集合请求参数 +// DatabaseCollectionReq 新增/删除集合请求参数 type DatabaseCollectionReq struct { - Env string `json:"env,omitempty"` //云环境ID - CollectionName string `json:"collection_name,omitempty"` //集合名称 + Env string `json:"env,omitempty"` // 云环境ID + CollectionName string `json:"collection_name,omitempty"` // 集合名称 } -//DatabaseCollectionGetReq 获取特定云环境下集合信息请求 +// DatabaseCollectionGetReq 获取特定云环境下集合信息请求 type DatabaseCollectionGetReq struct { - Env string `json:"env,omitempty"` //云环境ID - Limit int64 `json:"limit,omitempty"` //获取数量限制 - Offset int64 `json:"offset,omitempty"` //偏移量 + Env string `json:"env,omitempty"` // 云环境ID + Limit int64 `json:"limit,omitempty"` // 获取数量限制 + Offset int64 `json:"offset,omitempty"` // 偏移量 } -//DatabaseCollectionGetRes 获取特定云环境下集合信息结果 +// DatabaseCollectionGetRes 获取特定云环境下集合信息结果 type DatabaseCollectionGetRes struct { util.CommonError Pager struct { - Limit int64 `json:"limit"` //单次查询限制 - Offset int64 `json:"offset"` //偏移量 - Total int64 `json:"total"` //符合查询条件的记录总数 + Limit int64 `json:"limit"` // 单次查询限制 + Offset int64 `json:"offset"` // 偏移量 + Total int64 `json:"total"` // 符合查询条件的记录总数 } `json:"pager"` Collections []struct { - Name string `json:"name"` //集合名 - Count int64 `json:"count"` //表中文档数量 - Size int64 `json:"size"` //表的大小(即表中文档总大小),单位:字节 - IndexCount int64 `json:"index_count"` //索引数量 - IndexSize int64 `json:"index_size"` //索引占用大小,单位:字节 + Name string `json:"name"` // 集合名 + Count int64 `json:"count"` // 表中文档数量 + Size int64 `json:"size"` // 表的大小(即表中文档总大小),单位:字节 + IndexCount int64 `json:"index_count"` // 索引数量 + IndexSize int64 `json:"index_size"` // 索引占用大小,单位:字节 } `json:"collections"` } -//DatabaseReq 数据库插入/删除/更新/查询/统计记录请求参数 +// DatabaseReq 数据库插入/删除/更新/查询/统计记录请求参数 type DatabaseReq struct { - Env string `json:"env,omitempty"` //云环境ID - Query string `json:"query,omitempty"` //数据库操作语句 + Env string `json:"env,omitempty"` // 云环境ID + Query string `json:"query,omitempty"` // 数据库操作语句 } -//DatabaseAddRes 数据库插入记录返回结果 +// DatabaseAddRes 数据库插入记录返回结果 type DatabaseAddRes struct { util.CommonError - IDList []string `json:"id_list"` //插入成功的数据集合主键_id。 + IDList []string `json:"id_list"` // 插入成功的数据集合主键_id。 } -//DatabaseDeleteRes 数据库删除记录返回结果 +// DatabaseDeleteRes 数据库删除记录返回结果 type DatabaseDeleteRes struct { util.CommonError - Deleted int64 `json:"deleted"` //删除记录数量 + Deleted int64 `json:"deleted"` // 删除记录数量 } -//DatabaseUpdateRes 数据库更新记录返回结果 +// DatabaseUpdateRes 数据库更新记录返回结果 type DatabaseUpdateRes struct { util.CommonError - Matched int64 `json:"matched"` //更新条件匹配到的结果数 - Modified int64 `json:"modified"` //修改的记录数,注意:使用set操作新插入的数据不计入修改数目 + Matched int64 `json:"matched"` // 更新条件匹配到的结果数 + Modified int64 `json:"modified"` // 修改的记录数,注意:使用set操作新插入的数据不计入修改数目 ID string `json:"id"` } -//DatabaseQueryRes 数据库查询记录 返回结果 +// DatabaseQueryRes 数据库查询记录 返回结果 type DatabaseQueryRes struct { util.CommonError Pager struct { - Limit int64 `json:"limit"` //单次查询限制 - Offset int64 `json:"offset"` //偏移量 - Total int64 `json:"total"` //符合查询条件的记录总数 + Limit int64 `json:"limit"` // 单次查询限制 + Offset int64 `json:"offset"` // 偏移量 + Total int64 `json:"total"` // 符合查询条件的记录总数 } `json:"pager"` Data []string `json:"data"` } -//DatabaseCountRes 统计集合记录数或统计查询语句对应的结果记录数 返回结果 +// DatabaseCountRes 统计集合记录数或统计查询语句对应的结果记录数 返回结果 type DatabaseCountRes struct { util.CommonError - Count int64 `json:"count"` //记录数量 + Count int64 `json:"count"` // 记录数量 } -//DatabaseMigrateImport 数据库导入 +// DatabaseMigrateImport 数据库导入 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateImport.html func (tcb *Tcb) DatabaseMigrateImport(req *DatabaseMigrateImportReq) (*DatabaseMigrateImportRes, error) { accessToken, err := tcb.GetAccessToken() @@ -208,7 +208,7 @@ func (tcb *Tcb) DatabaseMigrateImport(req *DatabaseMigrateImportReq) (*DatabaseM return databaseMigrateImportRes, err } -//DatabaseMigrateExport 数据库导出 +// DatabaseMigrateExport 数据库导出 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateExport.html func (tcb *Tcb) DatabaseMigrateExport(req *DatabaseMigrateExportReq) (*DatabaseMigrateExportRes, error) { accessToken, err := tcb.GetAccessToken() @@ -225,7 +225,7 @@ func (tcb *Tcb) DatabaseMigrateExport(req *DatabaseMigrateExportReq) (*DatabaseM return databaseMigrateExportRes, err } -//DatabaseMigrateQueryInfo 数据库迁移状态查询 +// DatabaseMigrateQueryInfo 数据库迁移状态查询 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateQueryInfo.html func (tcb *Tcb) DatabaseMigrateQueryInfo(env string, jobID int64) (*DatabaseMigrateQueryInfoRes, error) { accessToken, err := tcb.GetAccessToken() @@ -245,8 +245,8 @@ func (tcb *Tcb) DatabaseMigrateQueryInfo(env string, jobID int64) (*DatabaseMigr return databaseMigrateQueryInfoRes, err } -//UpdateIndex 变更数据库索引 -//https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/updateIndex.html +// UpdateIndex 变更数据库索引 +// https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/updateIndex.html func (tcb *Tcb) UpdateIndex(req *UpdateIndexReq) error { accessToken, err := tcb.GetAccessToken() if err != nil { @@ -260,7 +260,7 @@ func (tcb *Tcb) UpdateIndex(req *UpdateIndexReq) error { return util.DecodeWithCommonError(response, "UpdateIndex") } -//DatabaseCollectionAdd 新增集合 +// DatabaseCollectionAdd 新增集合 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionAdd.html func (tcb *Tcb) DatabaseCollectionAdd(env, collectionName string) error { accessToken, err := tcb.GetAccessToken() @@ -278,7 +278,7 @@ func (tcb *Tcb) DatabaseCollectionAdd(env, collectionName string) error { return util.DecodeWithCommonError(response, "DatabaseCollectionAdd") } -//DatabaseCollectionDelete 删除集合 +// DatabaseCollectionDelete 删除集合 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionDelete.html func (tcb *Tcb) DatabaseCollectionDelete(env, collectionName string) error { accessToken, err := tcb.GetAccessToken() @@ -296,7 +296,7 @@ func (tcb *Tcb) DatabaseCollectionDelete(env, collectionName string) error { return util.DecodeWithCommonError(response, "DatabaseCollectionDelete") } -//DatabaseCollectionGet 获取特定云环境下集合信息 +// DatabaseCollectionGet 获取特定云环境下集合信息 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionGet.html func (tcb *Tcb) DatabaseCollectionGet(env string, limit, offset int64) (*DatabaseCollectionGetRes, error) { accessToken, err := tcb.GetAccessToken() @@ -317,7 +317,7 @@ func (tcb *Tcb) DatabaseCollectionGet(env string, limit, offset int64) (*Databas return databaseCollectionGetRes, err } -//DatabaseAdd 数据库插入记录 +// DatabaseAdd 数据库插入记录 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseAdd.html func (tcb *Tcb) DatabaseAdd(env, query string) (*DatabaseAddRes, error) { accessToken, err := tcb.GetAccessToken() @@ -337,7 +337,7 @@ func (tcb *Tcb) DatabaseAdd(env, query string) (*DatabaseAddRes, error) { return databaseAddRes, err } -//DatabaseDelete 数据库插入记录 +// DatabaseDelete 数据库插入记录 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseDelete.html func (tcb *Tcb) DatabaseDelete(env, query string) (*DatabaseDeleteRes, error) { accessToken, err := tcb.GetAccessToken() @@ -357,7 +357,7 @@ func (tcb *Tcb) DatabaseDelete(env, query string) (*DatabaseDeleteRes, error) { return databaseDeleteRes, err } -//DatabaseUpdate 数据库插入记录 +// DatabaseUpdate 数据库插入记录 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseUpdate.html func (tcb *Tcb) DatabaseUpdate(env, query string) (*DatabaseUpdateRes, error) { accessToken, err := tcb.GetAccessToken() @@ -377,7 +377,7 @@ func (tcb *Tcb) DatabaseUpdate(env, query string) (*DatabaseUpdateRes, error) { return databaseUpdateRes, err } -//DatabaseQuery 数据库查询记录 +// DatabaseQuery 数据库查询记录 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseQuery.html func (tcb *Tcb) DatabaseQuery(env, query string) (*DatabaseQueryRes, error) { accessToken, err := tcb.GetAccessToken() @@ -397,7 +397,7 @@ func (tcb *Tcb) DatabaseQuery(env, query string) (*DatabaseQueryRes, error) { return databaseQueryRes, err } -//DatabaseCount 统计集合记录数或统计查询语句对应的结果记录数 +// DatabaseCount 统计集合记录数或统计查询语句对应的结果记录数 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCount.html func (tcb *Tcb) DatabaseCount(env, query string) (*DatabaseCountRes, error) { accessToken, err := tcb.GetAccessToken() diff --git a/miniprogram/tcb/file.go b/miniprogram/tcb/file.go index 89c8c3e..cd011e7 100644 --- a/miniprogram/tcb/file.go +++ b/miniprogram/tcb/file.go @@ -7,60 +7,60 @@ import ( ) const ( - //获取文件上传链接 + // 获取文件上传链接 uploadFilePathURL = "https://api.weixin.qq.com/tcb/uploadfile" - //获取文件下载链接 + // 获取文件下载链接 batchDownloadFileURL = "https://api.weixin.qq.com/tcb/batchdownloadfile" - //删除文件链接 + // 删除文件链接 batchDeleteFileURL = "https://api.weixin.qq.com/tcb/batchdeletefile" ) -//UploadFileReq 上传文件请求值 +// UploadFileReq 上传文件请求值 type UploadFileReq struct { Env string `json:"env,omitempty"` Path string `json:"path,omitempty"` } -//UploadFileRes 上传文件返回结果 +// UploadFileRes 上传文件返回结果 type UploadFileRes struct { util.CommonError - URL string `json:"url"` //上传url - Token string `json:"token"` //token - Authorization string `json:"authorization"` //authorization - FileID string `json:"file_id"` //文件ID - CosFileID string `json:"cos_file_id"` //cos文件ID + URL string `json:"url"` // 上传url + Token string `json:"token"` // token + Authorization string `json:"authorization"` // authorization + FileID string `json:"file_id"` // 文件ID + CosFileID string `json:"cos_file_id"` // cos文件ID } -//BatchDownloadFileReq 上传文件请求值 +// BatchDownloadFileReq 上传文件请求值 type BatchDownloadFileReq struct { Env string `json:"env,omitempty"` FileList []*DownloadFile `json:"file_list,omitempty"` } -//DownloadFile 文件信息 +// DownloadFile 文件信息 type DownloadFile struct { - FileID string `json:"fileid"` //文件ID - MaxAge int64 `json:"max_age"` //下载链接有效期 + FileID string `json:"fileid"` // 文件ID + MaxAge int64 `json:"max_age"` // 下载链接有效期 } -//BatchDownloadFileRes 上传文件返回结果 +// BatchDownloadFileRes 上传文件返回结果 type BatchDownloadFileRes struct { util.CommonError FileList []struct { - FileID string `json:"file_id"` //文件ID - DownloadURL string `json:"download_url"` //下载链接 - Status int64 `json:"status"` //状态码 - ErrMsg string `json:"errmsg"` //该文件错误信息 + FileID string `json:"file_id"` // 文件ID + DownloadURL string `json:"download_url"` // 下载链接 + Status int64 `json:"status"` // 状态码 + ErrMsg string `json:"errmsg"` // 该文件错误信息 } `json:"file_list"` } -//BatchDeleteFileReq 批量删除文件请求参数 +// BatchDeleteFileReq 批量删除文件请求参数 type BatchDeleteFileReq struct { Env string `json:"env,omitempty"` FileIDList []string `json:"fileid_list,omitempty"` } -//BatchDeleteFileRes 批量删除文件返回结果 +// BatchDeleteFileRes 批量删除文件返回结果 type BatchDeleteFileRes struct { util.CommonError DeleteList []struct { @@ -70,7 +70,7 @@ type BatchDeleteFileRes struct { } `json:"delete_list"` } -//UploadFile 上传文件 +// UploadFile 上传文件 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/uploadFile.html func (tcb *Tcb) UploadFile(env, path string) (*UploadFileRes, error) { accessToken, err := tcb.GetAccessToken() @@ -91,7 +91,7 @@ func (tcb *Tcb) UploadFile(env, path string) (*UploadFileRes, error) { return uploadFileRes, err } -//BatchDownloadFile 获取文件下载链接 +// BatchDownloadFile 获取文件下载链接 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/batchDownloadFile.html func (tcb *Tcb) BatchDownloadFile(env string, fileList []*DownloadFile) (*BatchDownloadFileRes, error) { accessToken, err := tcb.GetAccessToken() @@ -112,7 +112,7 @@ func (tcb *Tcb) BatchDownloadFile(env string, fileList []*DownloadFile) (*BatchD return batchDownloadFileRes, err } -//BatchDeleteFile 批量删除文件 +// BatchDeleteFile 批量删除文件 //reference:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/batchDeleteFile.html func (tcb *Tcb) BatchDeleteFile(env string, fileIDList []string) (*BatchDeleteFileRes, error) { accessToken, err := tcb.GetAccessToken() diff --git a/miniprogram/tcb/tcb.go b/miniprogram/tcb/tcb.go index 35522ee..5f6cfd4 100644 --- a/miniprogram/tcb/tcb.go +++ b/miniprogram/tcb/tcb.go @@ -2,12 +2,12 @@ package tcb import "github.com/silenceper/wechat/v2/miniprogram/context" -//Tcb Tencent Cloud Base +// Tcb Tencent Cloud Base type Tcb struct { *context.Context } -//NewTcb new Tencent Cloud Base +// NewTcb new Tencent Cloud Base func NewTcb(context *context.Context) *Tcb { return &Tcb{ context, diff --git a/miniprogram/urllink/urllink.go b/miniprogram/urllink/urllink.go index c043ac2..c89aa7e 100644 --- a/miniprogram/urllink/urllink.go +++ b/miniprogram/urllink/urllink.go @@ -51,7 +51,6 @@ type ULResult struct { // Generate 生成url link func (u *URLLink) Generate(params *ULParams) (string, error) { - var accessToken string accessToken, err := u.GetAccessToken() if err != nil { return "", err diff --git a/officialaccount/basic/basic.go b/officialaccount/basic/basic.go index c0f02ba..756db97 100644 --- a/officialaccount/basic/basic.go +++ b/officialaccount/basic/basic.go @@ -8,34 +8,34 @@ import ( ) var ( - //获取微信服务器IP地址 - //文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_the_WeChat_server_IP_address.html + // 获取微信服务器IP地址 + // 文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_the_WeChat_server_IP_address.html getCallbackIPURL = "https://api.weixin.qq.com/cgi-bin/getcallbackip" getAPIDomainIPURL = "https://api.weixin.qq.com/cgi-bin/get_api_domain_ip" - //清理接口调用次数 + // 清理接口调用次数 clearQuotaURL = "https://api.weixin.qq.com/cgi-bin/clear_quota" ) -//Basic struct +// Basic struct type Basic struct { *context.Context } -//NewBasic 实例 +// NewBasic 实例 func NewBasic(context *context.Context) *Basic { basic := new(Basic) basic.Context = context return basic } -//IPListRes 获取微信服务器IP地址 返回结果 +// IPListRes 获取微信服务器IP地址 返回结果 type IPListRes struct { util.CommonError IPList []string `json:"ip_list"` } -//GetCallbackIP 获取微信callback IP地址 +// GetCallbackIP 获取微信callback IP地址 func (basic *Basic) GetCallbackIP() ([]string, error) { ak, err := basic.GetAccessToken() if err != nil { @@ -51,7 +51,7 @@ func (basic *Basic) GetCallbackIP() ([]string, error) { return ipListRes.IPList, err } -//GetAPIDomainIP 获取微信API接口 IP地址 +// GetAPIDomainIP 获取微信API接口 IP地址 func (basic *Basic) GetAPIDomainIP() ([]string, error) { ak, err := basic.GetAccessToken() if err != nil { @@ -67,7 +67,7 @@ func (basic *Basic) GetAPIDomainIP() ([]string, error) { return ipListRes.IPList, err } -//ClearQuota 清理接口调用次数 +// ClearQuota 清理接口调用次数 func (basic *Basic) ClearQuota() error { ak, err := basic.GetAccessToken() if err != nil { diff --git a/officialaccount/broadcast/broadcast.go b/officialaccount/broadcast/broadcast.go index 3093afa..885f683 100644 --- a/officialaccount/broadcast/broadcast.go +++ b/officialaccount/broadcast/broadcast.go @@ -17,42 +17,42 @@ const ( setSpeedSendURL = "https://api.weixin.qq.com/cgi-bin/message/mass/speed/set" ) -//MsgType 发送消息类型 +// MsgType 发送消息类型 type MsgType string const ( - //MsgTypeNews 图文消息 + // MsgTypeNews 图文消息 MsgTypeNews MsgType = "mpnews" - //MsgTypeText 文本 + // MsgTypeText 文本 MsgTypeText MsgType = "text" - //MsgTypeVoice 语音/音频 + // MsgTypeVoice 语音/音频 MsgTypeVoice MsgType = "voice" - //MsgTypeImage 图片 + // MsgTypeImage 图片 MsgTypeImage MsgType = "image" - //MsgTypeVideo 视频 + // MsgTypeVideo 视频 MsgTypeVideo MsgType = "mpvideo" - //MsgTypeWxCard 卡券 + // MsgTypeWxCard 卡券 MsgTypeWxCard MsgType = "wxcard" ) -//Broadcast 群发消息 +// Broadcast 群发消息 type Broadcast struct { *context.Context preview bool } -//NewBroadcast new +// NewBroadcast new func NewBroadcast(ctx *context.Context) *Broadcast { return &Broadcast{ctx, false} } -//User 发送的用户 +// User 发送的用户 type User struct { TagID int64 OpenID []string } -//Result 群发返回结果 +// Result 群发返回结果 type Result struct { util.CommonError MsgID int64 `json:"msg_id"` @@ -60,34 +60,34 @@ type Result struct { MsgStatus string `json:"msg_status"` } -//SpeedResult 群发速度返回结果 +// SpeedResult 群发速度返回结果 type SpeedResult struct { util.CommonError Speed int64 `json:"speed"` RealSpeed int64 `json:"realspeed"` } -//sendRequest 发送请求的数据 +// sendRequest 发送请求的数据 type sendRequest struct { - //根据tag获全部发送 + // 根据tag获全部发送 Filter map[string]interface{} `json:"filter,omitempty"` - //根据OpenID发送 + // 根据OpenID发送 ToUser interface{} `json:"touser,omitempty"` - //发送文本 + // 发送文本 Text map[string]interface{} `json:"text,omitempty"` - //发送图文消息 + // 发送图文消息 Mpnews map[string]interface{} `json:"mpnews,omitempty"` - //发送语音 + // 发送语音 Voice map[string]interface{} `json:"voice,omitempty"` - //发送图片 + // 发送图片 Images *Image `json:"images,omitempty"` - //发送卡券 + // 发送卡券 WxCard map[string]interface{} `json:"wxcard,omitempty"` MsgType MsgType `json:"msgtype"` SendIgnoreReprint int32 `json:"send_ignore_reprint,omitempty"` } -//Image 发送图片 +// Image 发送图片 type Image struct { MediaIDs []string `json:"media_ids"` Recommend string `json:"recommend"` @@ -95,10 +95,10 @@ type Image struct { OnlyFansCanComment int32 `json:"only_fans_can_comment"` } -//SendText 群发文本 -//user 为nil,表示全员发送 -//&User{TagID:2} 根据tag发送 -//&User{OpenID:[]string("xxx","xxx")} 根据openid发送 +// SendText 群发文本 +// user 为nil,表示全员发送 +// &User{TagID:2} 根据tag发送 +// &User{OpenID:[]string("xxx","xxx")} 根据openid发送 func (broadcast *Broadcast) SendText(user *User, content string) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { @@ -122,7 +122,7 @@ func (broadcast *Broadcast) SendText(user *User, content string) (*Result, error return res, err } -//SendNews 发送图文 +// SendNews 发送图文 func (broadcast *Broadcast) SendNews(user *User, mediaID string, ignoreReprint bool) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { @@ -149,7 +149,7 @@ func (broadcast *Broadcast) SendNews(user *User, mediaID string, ignoreReprint b return res, err } -//SendVoice 发送语音 +// SendVoice 发送语音 func (broadcast *Broadcast) SendVoice(user *User, mediaID string) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { @@ -173,7 +173,7 @@ func (broadcast *Broadcast) SendVoice(user *User, mediaID string) (*Result, erro return res, err } -//SendImage 发送图片 +// SendImage 发送图片 func (broadcast *Broadcast) SendImage(user *User, images *Image) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { @@ -195,7 +195,7 @@ func (broadcast *Broadcast) SendImage(user *User, images *Image) (*Result, error return res, err } -//SendVideo 发送视频 +// SendVideo 发送视频 func (broadcast *Broadcast) SendVideo(user *User, mediaID string, title, description string) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { @@ -221,7 +221,7 @@ func (broadcast *Broadcast) SendVideo(user *User, mediaID string, title, descrip return res, err } -//SendWxCard 发送卡券 +// SendWxCard 发送卡券 func (broadcast *Broadcast) SendWxCard(user *User, cardID string) (*Result, error) { ak, err := broadcast.GetAccessToken() if err != nil { @@ -245,7 +245,7 @@ func (broadcast *Broadcast) SendWxCard(user *User, cardID string) (*Result, erro return res, err } -//Delete 删除群发消息 +// Delete 删除群发消息 func (broadcast *Broadcast) Delete(msgID int64, articleIDx int64) error { ak, err := broadcast.GetAccessToken() if err != nil { diff --git a/officialaccount/config/config.go b/officialaccount/config/config.go index 7846801..b38fcce 100644 --- a/officialaccount/config/config.go +++ b/officialaccount/config/config.go @@ -4,11 +4,11 @@ import ( "github.com/silenceper/wechat/v2/cache" ) -// Config config for 微信公众号 +// Config .config for 微信公众号 type Config struct { - AppID string `json:"app_id"` //appid - AppSecret string `json:"app_secret"` //appsecret - Token string `json:"token"` //token - EncodingAESKey string `json:"encoding_aes_key"` //EncodingAESKey + AppID string `json:"app_id"` // appid + AppSecret string `json:"app_secret"` // appsecret + Token string `json:"token"` // token + EncodingAESKey string `json:"encoding_aes_key"` // EncodingAESKey Cache cache.Cache } diff --git a/officialaccount/datacube/broadcast.go b/officialaccount/datacube/broadcast.go index 4a3e1a4..7c11858 100644 --- a/officialaccount/datacube/broadcast.go +++ b/officialaccount/datacube/broadcast.go @@ -15,7 +15,7 @@ const ( getUserShareHour = "https://api.weixin.qq.com/datacube/getusersharehour" ) -//ResArticleSummary 获取图文群发每日数据响应 +// ResArticleSummary 获取图文群发每日数据响应 type ResArticleSummary struct { util.CommonError @@ -34,7 +34,7 @@ type ResArticleSummary struct { } `json:"list"` } -//ResArticleTotal 获取图文群发总数据响应 +// ResArticleTotal 获取图文群发总数据响应 type ResArticleTotal struct { util.CommonError @@ -46,7 +46,7 @@ type ResArticleTotal struct { } `json:"list"` } -//ArticleTotalDetails 获取图文群发总数据响应文字详情 +// ArticleTotalDetails 获取图文群发总数据响应文字详情 type ArticleTotalDetails struct { StatDate string `json:"stat_date"` TargetUser int `json:"target_user"` @@ -76,7 +76,7 @@ type ArticleTotalDetails struct { FeedShareFromOtherCnt int `json:"feed_share_from_other_cnt"` } -//ResUserRead 获取图文统计数据响应 +// ResUserRead 获取图文统计数据响应 type ResUserRead struct { util.CommonError @@ -94,7 +94,7 @@ type ResUserRead struct { } `json:"list"` } -//ResUserReadHour 获取图文统计分时数据 +// ResUserReadHour 获取图文统计分时数据 type ResUserReadHour struct { util.CommonError @@ -113,7 +113,7 @@ type ResUserReadHour struct { } `json:"list"` } -//ResUserShare 获取图文分享转发数据 +// ResUserShare 获取图文分享转发数据 type ResUserShare struct { util.CommonError @@ -125,7 +125,7 @@ type ResUserShare struct { } `json:"list"` } -//ResUserShareHour 获取图文分享转发分时数据 +// ResUserShareHour 获取图文分享转发分时数据 type ResUserShareHour struct { util.CommonError @@ -138,7 +138,7 @@ type ResUserShareHour struct { } `json:"list"` } -//GetArticleSummary 获取图文群发每日数据 +// GetArticleSummary 获取图文群发每日数据 func (cube *DataCube) GetArticleSummary(s string, e string) (resArticleSummary ResArticleSummary, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -160,7 +160,7 @@ func (cube *DataCube) GetArticleSummary(s string, e string) (resArticleSummary R return } -//GetArticleTotal 获取图文群发总数据 +// GetArticleTotal 获取图文群发总数据 func (cube *DataCube) GetArticleTotal(s string, e string) (resArticleTotal ResArticleTotal, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -182,7 +182,7 @@ func (cube *DataCube) GetArticleTotal(s string, e string) (resArticleTotal ResAr return } -//GetUserRead 获取图文统计数据 +// GetUserRead 获取图文统计数据 func (cube *DataCube) GetUserRead(s string, e string) (resUserRead ResUserRead, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -204,7 +204,7 @@ func (cube *DataCube) GetUserRead(s string, e string) (resUserRead ResUserRead, return } -//GetUserReadHour 获取图文统计分时数据 +// GetUserReadHour 获取图文统计分时数据 func (cube *DataCube) GetUserReadHour(s string, e string) (resUserReadHour ResUserReadHour, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -226,7 +226,7 @@ func (cube *DataCube) GetUserReadHour(s string, e string) (resUserReadHour ResUs return } -//GetUserShare 获取图文分享转发数据 +// GetUserShare 获取图文分享转发数据 func (cube *DataCube) GetUserShare(s string, e string) (resUserShare ResUserShare, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -248,7 +248,7 @@ func (cube *DataCube) GetUserShare(s string, e string) (resUserShare ResUserShar return } -//GetUserShareHour 获取图文分享转发分时数据 +// GetUserShareHour 获取图文分享转发分时数据 func (cube *DataCube) GetUserShareHour(s string, e string) (resUserShareHour ResUserShareHour, err error) { accessToken, err := cube.GetAccessToken() if err != nil { diff --git a/officialaccount/datacube/datacube.go b/officialaccount/datacube/datacube.go index 22e593d..3dd3af7 100644 --- a/officialaccount/datacube/datacube.go +++ b/officialaccount/datacube/datacube.go @@ -9,12 +9,12 @@ type reqDate struct { EndDate string `json:"end_date"` } -//DataCube 数据统计 +// DataCube 数据统计 type DataCube struct { *context.Context } -//NewCube 数据统计 +// NewCube 数据统计 func NewCube(context *context.Context) *DataCube { dataCube := new(DataCube) dataCube.Context = context diff --git a/officialaccount/datacube/interface.go b/officialaccount/datacube/interface.go index ea6f839..339308d 100644 --- a/officialaccount/datacube/interface.go +++ b/officialaccount/datacube/interface.go @@ -11,7 +11,7 @@ const ( getInterfaceSummaryHour = "https://api.weixin.qq.com/datacube/getinterfacesummaryhour" ) -//ResInterfaceSummary 接口分析数据响应 +// ResInterfaceSummary 接口分析数据响应 type ResInterfaceSummary struct { util.CommonError @@ -24,7 +24,7 @@ type ResInterfaceSummary struct { } `json:"list"` } -//ResInterfaceSummaryHour 接口分析分时数据响应 +// ResInterfaceSummaryHour 接口分析分时数据响应 type ResInterfaceSummaryHour struct { util.CommonError @@ -38,7 +38,7 @@ type ResInterfaceSummaryHour struct { } `json:"list"` } -//GetInterfaceSummary 获取接口分析数据 +// GetInterfaceSummary 获取接口分析数据 func (cube *DataCube) GetInterfaceSummary(s string, e string) (resInterfaceSummary ResInterfaceSummary, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -60,7 +60,7 @@ func (cube *DataCube) GetInterfaceSummary(s string, e string) (resInterfaceSumma return } -//GetInterfaceSummaryHour 获取接口分析分时数据 +// GetInterfaceSummaryHour 获取接口分析分时数据 func (cube *DataCube) GetInterfaceSummaryHour(s string, e string) (resInterfaceSummaryHour ResInterfaceSummaryHour, err error) { accessToken, err := cube.GetAccessToken() if err != nil { diff --git a/officialaccount/datacube/message.go b/officialaccount/datacube/message.go index 4ec3fd7..28f162b 100644 --- a/officialaccount/datacube/message.go +++ b/officialaccount/datacube/message.go @@ -16,7 +16,7 @@ const ( getUpstreamMsgDistMonth = "https://api.weixin.qq.com/datacube/getupstreammsgdistmonth" ) -//ResUpstreamMsg 获取消息发送概况数据响应 +// ResUpstreamMsg 获取消息发送概况数据响应 type ResUpstreamMsg struct { util.CommonError @@ -28,7 +28,7 @@ type ResUpstreamMsg struct { } `json:"list"` } -//ResUpstreamMsgHour 获取消息分送分时数据响应 +// ResUpstreamMsgHour 获取消息分送分时数据响应 type ResUpstreamMsgHour struct { util.CommonError @@ -41,7 +41,7 @@ type ResUpstreamMsgHour struct { } `json:"list"` } -//ResUpstreamMsgWeek 获取消息发送周数据响应 +// ResUpstreamMsgWeek 获取消息发送周数据响应 type ResUpstreamMsgWeek struct { util.CommonError @@ -53,7 +53,7 @@ type ResUpstreamMsgWeek struct { } `json:"list"` } -//ResUpstreamMsgMonth 获取消息发送月数据响应 +// ResUpstreamMsgMonth 获取消息发送月数据响应 type ResUpstreamMsgMonth struct { util.CommonError @@ -65,7 +65,7 @@ type ResUpstreamMsgMonth struct { } `json:"list"` } -//ResUpstreamMsgDist 获取消息发送分布数据响应 +// ResUpstreamMsgDist 获取消息发送分布数据响应 type ResUpstreamMsgDist struct { util.CommonError @@ -76,7 +76,7 @@ type ResUpstreamMsgDist struct { } `json:"list"` } -//ResUpstreamMsgDistWeek 获取消息发送分布周数据响应 +// ResUpstreamMsgDistWeek 获取消息发送分布周数据响应 type ResUpstreamMsgDistWeek struct { util.CommonError @@ -87,7 +87,7 @@ type ResUpstreamMsgDistWeek struct { } `json:"list"` } -//ResUpstreamMsgDistMonth 获取消息发送分布月数据响应 +// ResUpstreamMsgDistMonth 获取消息发送分布月数据响应 type ResUpstreamMsgDistMonth struct { util.CommonError @@ -98,7 +98,7 @@ type ResUpstreamMsgDistMonth struct { } `json:"list"` } -//GetUpstreamMsg 获取消息发送概况数据 +// GetUpstreamMsg 获取消息发送概况数据 func (cube *DataCube) GetUpstreamMsg(s string, e string) (resUpstreamMsg ResUpstreamMsg, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -120,7 +120,7 @@ func (cube *DataCube) GetUpstreamMsg(s string, e string) (resUpstreamMsg ResUpst return } -//GetUpstreamMsgHour 获取消息分送分时数据 +// GetUpstreamMsgHour 获取消息分送分时数据 func (cube *DataCube) GetUpstreamMsgHour(s string, e string) (resUpstreamMsgHour ResUpstreamMsgHour, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -142,7 +142,7 @@ func (cube *DataCube) GetUpstreamMsgHour(s string, e string) (resUpstreamMsgHour return } -//GetUpstreamMsgWeek 获取消息发送周数据 +// GetUpstreamMsgWeek 获取消息发送周数据 func (cube *DataCube) GetUpstreamMsgWeek(s string, e string) (resUpstreamMsgWeek ResUpstreamMsgWeek, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -164,7 +164,7 @@ func (cube *DataCube) GetUpstreamMsgWeek(s string, e string) (resUpstreamMsgWeek return } -//GetUpstreamMsgMonth 获取消息发送月数据 +// GetUpstreamMsgMonth 获取消息发送月数据 func (cube *DataCube) GetUpstreamMsgMonth(s string, e string) (resUpstreamMsgMonth ResUpstreamMsgMonth, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -186,7 +186,7 @@ func (cube *DataCube) GetUpstreamMsgMonth(s string, e string) (resUpstreamMsgMon return } -//GetUpstreamMsgDist 获取消息发送分布数据 +// GetUpstreamMsgDist 获取消息发送分布数据 func (cube *DataCube) GetUpstreamMsgDist(s string, e string) (resUpstreamMsgDist ResUpstreamMsgDist, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -208,7 +208,7 @@ func (cube *DataCube) GetUpstreamMsgDist(s string, e string) (resUpstreamMsgDist return } -//GetUpstreamMsgDistWeek 获取消息发送分布周数据 +// GetUpstreamMsgDistWeek 获取消息发送分布周数据 func (cube *DataCube) GetUpstreamMsgDistWeek(s string, e string) (resUpstreamMsgDistWeek ResUpstreamMsgDistWeek, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -230,7 +230,7 @@ func (cube *DataCube) GetUpstreamMsgDistWeek(s string, e string) (resUpstreamMsg return } -//GetUpstreamMsgDistMonth 获取消息发送分布月数据 +// GetUpstreamMsgDistMonth 获取消息发送分布月数据 func (cube *DataCube) GetUpstreamMsgDistMonth(s string, e string) (resUpstreamMsgDistMonth ResUpstreamMsgDistMonth, err error) { accessToken, err := cube.GetAccessToken() if err != nil { diff --git a/officialaccount/datacube/publisher.go b/officialaccount/datacube/publisher.go index 267a550..bd640d0 100644 --- a/officialaccount/datacube/publisher.go +++ b/officialaccount/datacube/publisher.go @@ -8,31 +8,31 @@ import ( "github.com/silenceper/wechat/v2/util" ) -//AdSlot 广告位类型 +// AdSlot 广告位类型 type AdSlot string const ( - //SlotIDBizBottom 公众号底部广告 + // SlotIDBizBottom 公众号底部广告 SlotIDBizBottom AdSlot = "SLOT_ID_BIZ_BOTTOM" - //SlotIDBizMidContext 公众号文中广告 + // SlotIDBizMidContext 公众号文中广告 SlotIDBizMidContext AdSlot = "SLOT_ID_BIZ_MID_CONTEXT" - //SlotIDBizVideoEnd 公众号视频后贴 + // SlotIDBizVideoEnd 公众号视频后贴 SlotIDBizVideoEnd AdSlot = "SLOT_ID_BIZ_VIDEO_END" - //SlotIDBizSponsor 公众号互选广告 + // SlotIDBizSponsor 公众号互选广告 SlotIDBizSponsor AdSlot = "SLOT_ID_BIZ_SPONSOR" - //SlotIDBizCps 公众号返佣商品 + // SlotIDBizCps 公众号返佣商品 SlotIDBizCps AdSlot = "SLOT_ID_BIZ_CPS" - //SlotIDWeappBanner 小程序banner + // SlotIDWeappBanner 小程序banner SlotIDWeappBanner AdSlot = "SLOT_ID_WEAPP_BANNER" - //SlotIDWeappRewardVideo 小程序激励视频 + // SlotIDWeappRewardVideo 小程序激励视频 SlotIDWeappRewardVideo AdSlot = "SLOT_ID_WEAPP_REWARD_VIDEO" - //SlotIDWeappInterstitial 小程序插屏广告 + // SlotIDWeappInterstitial 小程序插屏广告 SlotIDWeappInterstitial AdSlot = "SLOT_ID_WEAPP_INTERSTITIAL" - //SlotIDWeappVideoFeeds 小程序视频广告 + // SlotIDWeappVideoFeeds 小程序视频广告 SlotIDWeappVideoFeeds AdSlot = "SLOT_ID_WEAPP_VIDEO_FEEDS" - //SlotIDWeappVideoBegin 小程序视频前贴 + // SlotIDWeappVideoBegin 小程序视频前贴 SlotIDWeappVideoBegin AdSlot = "SLOT_ID_WEAPP_VIDEO_BEGIN" - //SlotIDWeappBox 小程序格子广告 + // SlotIDWeappBox 小程序格子广告 SlotIDWeappBox AdSlot = "SLOT_ID_WEAPP_BOX" ) @@ -46,13 +46,13 @@ const ( actionPublisherSettlement = "publisher_settlement" ) -//BaseResp 错误信息 +// BaseResp 错误信息 type BaseResp struct { ErrMsg string `json:"err_msg"` Ret int `json:"ret"` } -//ResPublisherAdPos 公众号分广告位数据响应 +// ResPublisherAdPos 公众号分广告位数据响应 type ResPublisherAdPos struct { util.CommonError @@ -62,7 +62,7 @@ type ResPublisherAdPos struct { TotalNum int `json:"total_num"` } -//ResAdPosList 公众号分广告位列表 +// ResAdPosList 公众号分广告位列表 type ResAdPosList struct { SlotID int64 `json:"slot_id"` AdSlot string `json:"ad_slot"` @@ -76,7 +76,7 @@ type ResAdPosList struct { Ecpm float64 `json:"ecpm"` } -//ResAdPosSummary 公众号分广告位概览 +// ResAdPosSummary 公众号分广告位概览 type ResAdPosSummary struct { ReqSuccCount int `json:"req_succ_count"` ExposureCount int `json:"exposure_count"` @@ -87,7 +87,7 @@ type ResAdPosSummary struct { Ecpm float64 `json:"ecpm"` } -//ResPublisherCps 公众号返佣商品数据响应 +// ResPublisherCps 公众号返佣商品数据响应 type ResPublisherCps struct { util.CommonError @@ -97,7 +97,7 @@ type ResPublisherCps struct { TotalNum int `json:"total_num"` } -//ResCpsList 公众号返佣商品列表 +// ResCpsList 公众号返佣商品列表 type ResCpsList struct { Date string `json:"date"` ExposureCount int `json:"exposure_count"` @@ -109,7 +109,7 @@ type ResCpsList struct { TotalCommission int `json:"total_commission"` } -//ResCpsSummary 公众号返佣概览 +// ResCpsSummary 公众号返佣概览 type ResCpsSummary struct { ExposureCount int `json:"exposure_count"` ClickCount int `json:"click_count"` @@ -120,7 +120,7 @@ type ResCpsSummary struct { TotalCommission int `json:"total_commission"` } -//ResPublisherSettlement 公众号结算收入数据及结算主体信息响应 +// ResPublisherSettlement 公众号结算收入数据及结算主体信息响应 type ResPublisherSettlement struct { util.CommonError @@ -133,7 +133,7 @@ type ResPublisherSettlement struct { TotalNum int `json:"total_num"` } -//SettlementList 结算单列表 +// SettlementList 结算单列表 type SettlementList struct { Date string `json:"date"` Zone string `json:"zone"` @@ -146,13 +146,13 @@ type SettlementList struct { SlotRevenue []SlotRevenue `json:"slot_revenue"` } -//SlotRevenue 产生收入的广告 +// SlotRevenue 产生收入的广告 type SlotRevenue struct { SlotID string `json:"slot_id"` SlotSettledRevenue int `json:"slot_settled_revenue"` } -//ParamsPublisher 拉取数据参数 +// ParamsPublisher 拉取数据参数 type ParamsPublisher struct { Action string `json:"action"` StartDate string `json:"start_date"` @@ -189,7 +189,7 @@ func (cube *DataCube) fetchData(params ParamsPublisher) (response []byte, err er return } -//GetPublisherAdPosGeneral 获取公众号分广告位数据 +// GetPublisherAdPosGeneral 获取公众号分广告位数据 func (cube *DataCube) GetPublisherAdPosGeneral(startDate, endDate string, page, pageSize int, adSlot AdSlot) (resPublisherAdPos ResPublisherAdPos, err error) { params := ParamsPublisher{ Action: actionPublisherAdPosGeneral, @@ -217,7 +217,7 @@ func (cube *DataCube) GetPublisherAdPosGeneral(startDate, endDate string, page, return } -//GetPublisherCpsGeneral 获取公众号返佣商品数据 +// GetPublisherCpsGeneral 获取公众号返佣商品数据 func (cube *DataCube) GetPublisherCpsGeneral(startDate, endDate string, page, pageSize int) (resPublisherCps ResPublisherCps, err error) { params := ParamsPublisher{ Action: actionPublisherCpsGeneral, @@ -244,7 +244,7 @@ func (cube *DataCube) GetPublisherCpsGeneral(startDate, endDate string, page, pa return } -//GetPublisherSettlement 获取公众号结算收入数据及结算主体信息 +// GetPublisherSettlement 获取公众号结算收入数据及结算主体信息 func (cube *DataCube) GetPublisherSettlement(startDate, endDate string, page, pageSize int) (resPublisherSettlement ResPublisherSettlement, err error) { params := ParamsPublisher{ Action: actionPublisherSettlement, diff --git a/officialaccount/datacube/user.go b/officialaccount/datacube/user.go index e4242d0..a24fbc4 100644 --- a/officialaccount/datacube/user.go +++ b/officialaccount/datacube/user.go @@ -11,7 +11,7 @@ const ( getUserAccumulate = "https://api.weixin.qq.com/datacube/getusercumulate" ) -//ResUserSummary 获取用户增减数据响应 +// ResUserSummary 获取用户增减数据响应 type ResUserSummary struct { util.CommonError @@ -23,7 +23,7 @@ type ResUserSummary struct { } `json:"list"` } -//ResUserAccumulate 获取累计用户数据响应 +// ResUserAccumulate 获取累计用户数据响应 type ResUserAccumulate struct { util.CommonError @@ -33,7 +33,7 @@ type ResUserAccumulate struct { } `json:"list"` } -//GetUserSummary 获取用户增减数据 +// GetUserSummary 获取用户增减数据 func (cube *DataCube) GetUserSummary(s string, e string) (resUserSummary ResUserSummary, err error) { accessToken, err := cube.GetAccessToken() if err != nil { @@ -55,7 +55,7 @@ func (cube *DataCube) GetUserSummary(s string, e string) (resUserSummary ResUser return } -//GetUserAccumulate 获取累计用户数据 +// GetUserAccumulate 获取累计用户数据 func (cube *DataCube) GetUserAccumulate(s string, e string) (resUserAccumulate ResUserAccumulate, err error) { accessToken, err := cube.GetAccessToken() if err != nil { diff --git a/officialaccount/device/authorize.go b/officialaccount/device/authorize.go index 1368356..4f1b6bf 100644 --- a/officialaccount/device/authorize.go +++ b/officialaccount/device/authorize.go @@ -1,4 +1,4 @@ -//Package device 设备相关接口 +// Package device 设备相关接口 package device import ( @@ -23,13 +23,13 @@ type reqDeviceAuthorize struct { // 请求操作的类型,限定取值为:0:设备授权(缺省值为0) 1:设备更新(更新已授权设备的各属性值) OpType string `json:"op_type,omitempty"` // 设备的产品编号(由微信硬件平台分配)。可在公众号设备功能管理页面查询。 - //当 op_type 为‘0’,product_id 为‘1’时,不要填写 product_id 字段(会引起不必要错误); - //当 op_typy 为‘0’,product_id 不为‘1’时,必须填写 product_id 字段; - //当 op_type 为 1 时,不要填写 product_id 字段。 + // 当 op_type 为‘0’,product_id 为‘1’时,不要填写 product_id 字段(会引起不必要错误); + // 当 op_typy 为‘0’,product_id 不为‘1’时,必须填写 product_id 字段; + // 当 op_type 为 1 时,不要填写 product_id 字段。 ProductID string `json:"product_id,omitempty"` } -//ReqDevice 设备授权实体 +// ReqDevice 设备授权实体 type ReqDevice struct { // 设备的 device id ID string `json:"id"` @@ -45,13 +45,13 @@ type ReqDevice struct { // 1:表示设备仅支持andiod classic bluetooth 1|2:表示设备支持android 和ios 两种classic bluetooth,但是客户端优先选择android classic bluetooth 协议,如果android classic bluetooth协议连接失败,再选择ios classic bluetooth协议进行连接 // (注:安卓平台不同时支持BLE和classic类型) ConnectProtocol string `json:"connect_protocol"` - //auth及通信的加密key,第三方需要将key烧制在设备上(128bit),格式采用16进制串的方式(长度为32字节),不需要0X前缀,如: 1234567890ABCDEF1234567890ABCDEF + // auth及通信的加密key,第三方需要将key烧制在设备上(128bit),格式采用16进制串的方式(长度为32字节),不需要0X前缀,如: 1234567890ABCDEF1234567890ABCDEF AuthKey string `json:"auth_key"` // 断开策略,目前支持: 1:退出公众号页面时即断开连接 2:退出公众号之后保持连接不断开 CloseStrategy string `json:"close_strategy"` - //连接策略,32位整型,按bit位置位,目前仅第1bit和第3bit位有效(bit置0为无效,1为有效;第2bit已被废弃),且bit位可以按或置位(如1|4=5),各bit置位含义说明如下: - //1:(第1bit置位)在公众号对话页面,不停的尝试连接设备 - //4:(第3bit置位)处于非公众号页面(如主界面等),微信自动连接。当用户切换微信到前台时,可能尝试去连接设备,连上后一定时间会断开 + // 连接策略,32位整型,按bit位置位,目前仅第1bit和第3bit位有效(bit置0为无效,1为有效;第2bit已被废弃),且bit位可以按或置位(如1|4=5),各bit置位含义说明如下: + // 1:(第1bit置位)在公众号对话页面,不停的尝试连接设备 + // 4:(第3bit置位)处于非公众号页面(如主界面等),微信自动连接。当用户切换微信到前台时,可能尝试去连接设备,连上后一定时间会断开 ConnStrategy string `json:"conn_strategy"` // auth version,设备和微信进行auth时,会根据该版本号来确认auth buf和auth key的格式(各version对应的auth buf及key的具体格式可以参看“客户端蓝牙外设协议”),该字段目前支持取值: // 0:不加密的version @@ -69,7 +69,7 @@ type ReqDevice struct { BleSimpleProtocol string `json:"ble_simple_protocol,omitempty"` } -//ResBaseInfo 授权回调实体 +// ResBaseInfo 授权回调实体 type ResBaseInfo struct { BaseInfo struct { DeviceType string `json:"device_type"` diff --git a/officialaccount/device/device.go b/officialaccount/device/device.go index 327add4..75ef235 100644 --- a/officialaccount/device/device.go +++ b/officialaccount/device/device.go @@ -19,12 +19,12 @@ const ( uriState = "https://api.weixin.qq.com/device/get_stat" ) -//Device struct +// Device struct type Device struct { *context.Context } -//NewDevice 实例 +// NewDevice 实例 func NewDevice(context *context.Context) *Device { device := new(Device) device.Context = context diff --git a/officialaccount/device/message.go b/officialaccount/device/message.go index 7efcbbb..4e79097 100644 --- a/officialaccount/device/message.go +++ b/officialaccount/device/message.go @@ -1,6 +1,6 @@ package device -//MsgDevice 设备消息响应 +// MsgDevice 设备消息响应 type MsgDevice struct { DeviceType string DeviceID string diff --git a/officialaccount/device/qrcode.go b/officialaccount/device/qrcode.go index c77d659..89c21f3 100644 --- a/officialaccount/device/qrcode.go +++ b/officialaccount/device/qrcode.go @@ -7,7 +7,7 @@ import ( "github.com/silenceper/wechat/v2/util" ) -//ResCreateQRCode 获取二维码的返回实体 +// ResCreateQRCode 获取二维码的返回实体 type ResCreateQRCode struct { util.CommonError DeviceNum int `json:"device_num"` @@ -42,7 +42,7 @@ func (d *Device) CreateQRCode(devices []string) (res ResCreateQRCode, err error) return } -//ResVerifyQRCode 验证授权结果实体 +// ResVerifyQRCode 验证授权结果实体 type ResVerifyQRCode struct { util.CommonError DeviceType string `json:"device_type"` diff --git a/officialaccount/js/js.go b/officialaccount/js/js.go index a2a0683..e1c749f 100644 --- a/officialaccount/js/js.go +++ b/officialaccount/js/js.go @@ -22,7 +22,7 @@ type Config struct { Signature string `json:"signature"` } -//NewJs init +// NewJs init func NewJs(context *context.Context) *Js { js := new(Js) js.Context = context @@ -31,13 +31,13 @@ func NewJs(context *context.Context) *Js { return js } -//SetJsTicketHandle 自定义js ticket取值方式 +// SetJsTicketHandle 自定义js ticket取值方式 func (js *Js) SetJsTicketHandle(ticketHandle credential.JsTicketHandle) { js.JsTicketHandle = ticketHandle } -//GetConfig 获取jssdk需要的配置参数 -//uri 为当前网页地址 +// GetConfig 获取jssdk需要的配置参数 +// uri 为当前网页地址 func (js *Js) GetConfig(uri string) (config *Config, err error) { config = new(Config) var accessToken string diff --git a/officialaccount/material/material.go b/officialaccount/material/material.go index eaaad7e..a4da9b0 100644 --- a/officialaccount/material/material.go +++ b/officialaccount/material/material.go @@ -19,33 +19,33 @@ const ( batchGetMaterialURL = "https://api.weixin.qq.com/cgi-bin/material/batchget_material" ) -//PermanentMaterialType 永久素材类型 +// PermanentMaterialType 永久素材类型 type PermanentMaterialType string const ( - //PermanentMaterialTypeImage 永久素材图片类型(image) + // PermanentMaterialTypeImage 永久素材图片类型(image) PermanentMaterialTypeImage PermanentMaterialType = "image" - //PermanentMaterialTypeVideo 永久素材视频类型(video) + // PermanentMaterialTypeVideo 永久素材视频类型(video) PermanentMaterialTypeVideo PermanentMaterialType = "video" - //PermanentMaterialTypeVoice 永久素材语音类型 (voice) + // PermanentMaterialTypeVoice 永久素材语音类型 (voice) PermanentMaterialTypeVoice PermanentMaterialType = "voice" - //PermanentMaterialTypeNews 永久素材图文类型(news) + // PermanentMaterialTypeNews 永久素材图文类型(news) PermanentMaterialTypeNews PermanentMaterialType = "news" ) -//Material 素材管理 +// Material 素材管理 type Material struct { *context.Context } -//NewMaterial init +// NewMaterial init func NewMaterial(context *context.Context) *Material { material := new(Material) material.Context = context return material } -//Article 永久图文素材 +// Article 永久图文素材 type Article struct { Title string `json:"title"` ThumbMediaID string `json:"thumb_media_id"` @@ -87,19 +87,19 @@ func (material *Material) GetNews(id string) ([]*Article, error) { return res.NewsItem, nil } -//reqArticles 永久性图文素材请求信息 +// reqArticles 永久性图文素材请求信息 type reqArticles struct { Articles []*Article `json:"articles"` } -//resArticles 永久性图文素材返回结果 +// resArticles 永久性图文素材返回结果 type resArticles struct { util.CommonError MediaID string `json:"media_id"` } -//AddNews 新增永久图文素材 +// AddNews 新增永久图文素材 func (material *Material) AddNews(articles []*Article) (mediaID string, err error) { req := &reqArticles{articles} @@ -126,7 +126,7 @@ func (material *Material) AddNews(articles []*Article) (mediaID string, err erro return } -//reqUpdateArticle 更新永久性图文素材请求信息 +// reqUpdateArticle 更新永久性图文素材请求信息 type reqUpdateArticle struct { MediaID string `json:"media_id"` Index int64 `json:"index"` @@ -152,7 +152,7 @@ func (material *Material) UpdateNews(article *Article, mediaID string, index int return util.DecodeWithCommonError(response, "UpdateNews") } -//resAddMaterial 永久性素材上传返回的结果 +// resAddMaterial 永久性素材上传返回的结果 type resAddMaterial struct { util.CommonError @@ -160,7 +160,7 @@ type resAddMaterial struct { URL string `json:"url"` } -//AddMaterial 上传永久性素材(处理视频需要单独上传) +// AddMaterial 上传永久性素材(处理视频需要单独上传) func (material *Material) AddMaterial(mediaType MediaType, filename string) (mediaID string, url string, err error) { if mediaType == MediaTypeVideo { err = errors.New("永久视频素材上传使用 AddVideo 方法") @@ -197,7 +197,7 @@ type reqVideo struct { Introduction string `json:"introduction"` } -//AddVideo 永久视频素材文件上传 +// AddVideo 永久视频素材文件上传 func (material *Material) AddVideo(filename, title, introduction string) (mediaID string, url string, err error) { var accessToken string accessToken, err = material.GetAccessToken() @@ -254,7 +254,7 @@ type reqDeleteMaterial struct { MediaID string `json:"media_id"` } -//DeleteMaterial 删除永久素材 +// DeleteMaterial 删除永久素材 func (material *Material) DeleteMaterial(mediaID string) error { accessToken, err := material.GetAccessToken() if err != nil { @@ -270,7 +270,7 @@ func (material *Material) DeleteMaterial(mediaID string) error { return util.DecodeWithCommonError(response, "DeleteMaterial") } -//ArticleList 永久素材列表 +// ArticleList 永久素材列表 type ArticleList struct { util.CommonError TotalCount int64 `json:"total_count"` @@ -278,7 +278,7 @@ type ArticleList struct { Item []ArticleListItem `json:"item"` } -//ArticleListItem 用于ArticleList的item节点 +// ArticleListItem 用于ArticleList的item节点 type ArticleListItem struct { MediaID string `json:"media_id"` Content ArticleListContent `json:"content"` @@ -287,14 +287,14 @@ type ArticleListItem struct { UpdateTime int64 `json:"update_time"` } -//ArticleListContent 用于ArticleListItem的content节点 +// ArticleListContent 用于ArticleListItem的content节点 type ArticleListContent struct { NewsItem []Article `json:"news_item"` UpdateTime int64 `json:"update_time"` CreateTime int64 `json:"create_time"` } -//reqBatchGetMaterial BatchGetMaterial请求参数 +// reqBatchGetMaterial BatchGetMaterial请求参数 type reqBatchGetMaterial struct { Type PermanentMaterialType `json:"type"` Count int64 `json:"count"` diff --git a/officialaccount/material/media.go b/officialaccount/material/media.go index f5827cc..316758f 100644 --- a/officialaccount/material/media.go +++ b/officialaccount/material/media.go @@ -7,17 +7,17 @@ import ( "github.com/silenceper/wechat/v2/util" ) -//MediaType 媒体文件类型 +// MediaType 媒体文件类型 type MediaType string const ( - //MediaTypeImage 媒体文件:图片 + // MediaTypeImage 媒体文件:图片 MediaTypeImage MediaType = "image" - //MediaTypeVoice 媒体文件:声音 + // MediaTypeVoice 媒体文件:声音 MediaTypeVoice MediaType = "voice" - //MediaTypeVideo 媒体文件:视频 + // MediaTypeVideo 媒体文件:视频 MediaTypeVideo MediaType = "video" - //MediaTypeThumb 媒体文件:缩略图 + // MediaTypeThumb 媒体文件:缩略图 MediaTypeThumb MediaType = "thumb" ) @@ -27,7 +27,7 @@ const ( mediaGetURL = "https://api.weixin.qq.com/cgi-bin/media/get" ) -//Media 临时素材上传返回信息 +// Media 临时素材上传返回信息 type Media struct { util.CommonError @@ -37,7 +37,7 @@ type Media struct { CreatedAt int64 `json:"created_at"` } -//MediaUpload 临时素材上传 +// MediaUpload 临时素材上传 func (material *Material) MediaUpload(mediaType MediaType, filename string) (media Media, err error) { var accessToken string accessToken, err = material.GetAccessToken() @@ -62,8 +62,8 @@ func (material *Material) MediaUpload(mediaType MediaType, filename string) (med return } -//GetMediaURL 返回临时素材的下载地址供用户自己处理 -//NOTICE: URL 不可公开,因为含access_token 需要立即另存文件 +// GetMediaURL 返回临时素材的下载地址供用户自己处理 +// NOTICE: URL 不可公开,因为含access_token 需要立即另存文件 func (material *Material) GetMediaURL(mediaID string) (mediaURL string, err error) { var accessToken string accessToken, err = material.GetAccessToken() @@ -74,14 +74,14 @@ func (material *Material) GetMediaURL(mediaID string) (mediaURL string, err erro return } -//resMediaImage 图片上传返回结果 +// resMediaImage 图片上传返回结果 type resMediaImage struct { util.CommonError URL string `json:"url"` } -//ImageUpload 图片上传 +// ImageUpload 图片上传 func (material *Material) ImageUpload(filename string) (url string, err error) { var accessToken string accessToken, err = material.GetAccessToken() diff --git a/officialaccount/menu/button.go b/officialaccount/menu/button.go index 9956308..6b702db 100644 --- a/officialaccount/menu/button.go +++ b/officialaccount/menu/button.go @@ -1,6 +1,6 @@ package menu -//Button 菜单按钮 +// Button 菜单按钮 type Button struct { Type string `json:"type,omitempty"` Name string `json:"name,omitempty"` @@ -12,7 +12,7 @@ type Button struct { SubButtons []*Button `json:"sub_button,omitempty"` } -//SetSubButton 设置二级菜单 +// SetSubButton 设置二级菜单 func (btn *Button) SetSubButton(name string, subButtons []*Button) *Button { btn.Name = name btn.SubButtons = subButtons @@ -23,7 +23,7 @@ func (btn *Button) SetSubButton(name string, subButtons []*Button) *Button { return btn } -//SetClickButton btn 为click类型 +// SetClickButton btn 为click类型 func (btn *Button) SetClickButton(name, key string) *Button { btn.Type = "click" btn.Name = name @@ -34,7 +34,7 @@ func (btn *Button) SetClickButton(name, key string) *Button { return btn } -//SetViewButton view类型 +// SetViewButton view类型 func (btn *Button) SetViewButton(name, url string) *Button { btn.Type = "view" btn.Name = name @@ -45,7 +45,7 @@ func (btn *Button) SetViewButton(name, url string) *Button { return btn } -//SetScanCodePushButton 扫码推事件 +// SetScanCodePushButton 扫码推事件 func (btn *Button) SetScanCodePushButton(name, key string) *Button { btn.Type = "scancode_push" btn.Name = name @@ -56,7 +56,7 @@ func (btn *Button) SetScanCodePushButton(name, key string) *Button { return btn } -//SetScanCodeWaitMsgButton 设置 扫码推事件且弹出"消息接收中"提示框 +// SetScanCodeWaitMsgButton 设置 扫码推事件且弹出"消息接收中"提示框 func (btn *Button) SetScanCodeWaitMsgButton(name, key string) *Button { btn.Type = "scancode_waitmsg" btn.Name = name @@ -68,7 +68,7 @@ func (btn *Button) SetScanCodeWaitMsgButton(name, key string) *Button { return btn } -//SetPicSysPhotoButton 设置弹出系统拍照发图按钮 +// SetPicSysPhotoButton 设置弹出系统拍照发图按钮 func (btn *Button) SetPicSysPhotoButton(name, key string) *Button { btn.Type = "pic_sysphoto" btn.Name = name @@ -80,7 +80,7 @@ func (btn *Button) SetPicSysPhotoButton(name, key string) *Button { return btn } -//SetPicPhotoOrAlbumButton 设置弹出拍照或者相册发图类型按钮 +// SetPicPhotoOrAlbumButton 设置弹出拍照或者相册发图类型按钮 func (btn *Button) SetPicPhotoOrAlbumButton(name, key string) *Button { btn.Type = "pic_photo_or_album" btn.Name = name @@ -92,7 +92,7 @@ func (btn *Button) SetPicPhotoOrAlbumButton(name, key string) *Button { return btn } -//SetPicWeixinButton 设置弹出微信相册发图器类型按钮 +// SetPicWeixinButton 设置弹出微信相册发图器类型按钮 func (btn *Button) SetPicWeixinButton(name, key string) *Button { btn.Type = "pic_weixin" btn.Name = name @@ -104,7 +104,7 @@ func (btn *Button) SetPicWeixinButton(name, key string) *Button { return btn } -//SetLocationSelectButton 设置 弹出地理位置选择器 类型按钮 +// SetLocationSelectButton 设置 弹出地理位置选择器 类型按钮 func (btn *Button) SetLocationSelectButton(name, key string) *Button { btn.Type = "location_select" btn.Name = name @@ -116,7 +116,7 @@ func (btn *Button) SetLocationSelectButton(name, key string) *Button { return btn } -//SetMediaIDButton 设置 下发消息(除文本消息) 类型按钮 +// SetMediaIDButton 设置 下发消息(除文本消息) 类型按钮 func (btn *Button) SetMediaIDButton(name, mediaID string) *Button { btn.Type = "media_id" btn.Name = name @@ -128,7 +128,7 @@ func (btn *Button) SetMediaIDButton(name, mediaID string) *Button { return btn } -//SetViewLimitedButton 设置 跳转图文消息URL 类型按钮 +// SetViewLimitedButton 设置 跳转图文消息URL 类型按钮 func (btn *Button) SetViewLimitedButton(name, mediaID string) *Button { btn.Type = "view_limited" btn.Name = name @@ -140,7 +140,7 @@ func (btn *Button) SetViewLimitedButton(name, mediaID string) *Button { return btn } -//SetMiniprogramButton 设置 跳转小程序 类型按钮 (公众号后台必须已经关联小程序) +// SetMiniprogramButton 设置 跳转小程序 类型按钮 (公众号后台必须已经关联小程序) func (btn *Button) SetMiniprogramButton(name, url, appID, pagePath string) *Button { btn.Type = "miniprogram" btn.Name = name @@ -154,62 +154,62 @@ func (btn *Button) SetMiniprogramButton(name, url, appID, pagePath string) *Butt return btn } -//NewSubButton 二级菜单 +// NewSubButton 二级菜单 func NewSubButton(name string, subButtons []*Button) *Button { return (&Button{}).SetSubButton(name, subButtons) } -//NewClickButton btn 为click类型 +// NewClickButton btn 为click类型 func NewClickButton(name, key string) *Button { return (&Button{}).SetClickButton(name, key) } -//NewViewButton view类型 +// NewViewButton view类型 func NewViewButton(name, url string) *Button { return (&Button{}).SetViewButton(name, url) } -//NewScanCodePushButton 扫码推事件 +// NewScanCodePushButton 扫码推事件 func NewScanCodePushButton(name, key string) *Button { return (&Button{}).SetScanCodePushButton(name, key) } -//NewScanCodeWaitMsgButton 扫码推事件且弹出"消息接收中"提示框 +// NewScanCodeWaitMsgButton 扫码推事件且弹出"消息接收中"提示框 func NewScanCodeWaitMsgButton(name, key string) *Button { return (&Button{}).SetScanCodeWaitMsgButton(name, key) } -//NewPicSysPhotoButton 弹出系统拍照发图按钮 +// NewPicSysPhotoButton 弹出系统拍照发图按钮 func NewPicSysPhotoButton(name, key string) *Button { return (&Button{}).SetPicSysPhotoButton(name, key) } -//NewPicPhotoOrAlbumButton 弹出拍照或者相册发图类型按钮 +// NewPicPhotoOrAlbumButton 弹出拍照或者相册发图类型按钮 func NewPicPhotoOrAlbumButton(name, key string) *Button { return (&Button{}).SetPicPhotoOrAlbumButton(name, key) } -//NewPicWeixinButton 弹出微信相册发图器类型按钮 +// NewPicWeixinButton 弹出微信相册发图器类型按钮 func NewPicWeixinButton(name, key string) *Button { return (&Button{}).SetPicWeixinButton(name, key) } -//NewLocationSelectButton 弹出地理位置选择器 类型按钮 +// NewLocationSelectButton 弹出地理位置选择器 类型按钮 func NewLocationSelectButton(name, key string) *Button { return (&Button{}).SetLocationSelectButton(name, key) } -//NewMediaIDButton 下发消息(除文本消息) 类型按钮 +// NewMediaIDButton 下发消息(除文本消息) 类型按钮 func NewMediaIDButton(name, mediaID string) *Button { return (&Button{}).SetMediaIDButton(name, mediaID) } -//NewViewLimitedButton 跳转图文消息URL 类型按钮 +// NewViewLimitedButton 跳转图文消息URL 类型按钮 func NewViewLimitedButton(name, mediaID string) *Button { return (&Button{}).SetViewLimitedButton(name, mediaID) } -//NewMiniprogramButton 跳转小程序 类型按钮 (公众号后台必须已经关联小程序) +// NewMiniprogramButton 跳转小程序 类型按钮 (公众号后台必须已经关联小程序) func NewMiniprogramButton(name, url, appID, pagePath string) *Button { return (&Button{}).SetMiniprogramButton(name, url, appID, pagePath) } diff --git a/officialaccount/menu/menu.go b/officialaccount/menu/menu.go index 7454072..4739723 100644 --- a/officialaccount/menu/menu.go +++ b/officialaccount/menu/menu.go @@ -18,42 +18,42 @@ const ( menuSelfMenuInfoURL = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info" ) -//Menu struct +// Menu struct type Menu struct { *context.Context } -//reqMenu 设置菜单请求数据 +// reqMenu 设置菜单请求数据 type reqMenu struct { Button []*Button `json:"button,omitempty"` MatchRule *MatchRule `json:"matchrule,omitempty"` } -//reqDeleteConditional 删除个性化菜单请求数据 +// reqDeleteConditional 删除个性化菜单请求数据 type reqDeleteConditional struct { MenuID int64 `json:"menuid"` } -//reqMenuTryMatch 菜单匹配请求 +// reqMenuTryMatch 菜单匹配请求 type reqMenuTryMatch struct { UserID string `json:"user_id"` } -//resConditionalMenu 个性化菜单返回结果 +// resConditionalMenu 个性化菜单返回结果 type resConditionalMenu struct { Button []Button `json:"button"` MatchRule MatchRule `json:"matchrule"` MenuID int64 `json:"menuid"` } -//resMenuTryMatch 菜单匹配请求结果 +// resMenuTryMatch 菜单匹配请求结果 type resMenuTryMatch struct { util.CommonError Button []Button `json:"button"` } -//ResMenu 查询菜单的返回数据 +// ResMenu 查询菜单的返回数据 type ResMenu struct { util.CommonError @@ -64,7 +64,7 @@ type ResMenu struct { Conditionalmenu []resConditionalMenu `json:"conditionalmenu"` } -//ResSelfMenuInfo 自定义菜单配置返回结果 +// ResSelfMenuInfo 自定义菜单配置返回结果 type ResSelfMenuInfo struct { util.CommonError @@ -74,7 +74,7 @@ type ResSelfMenuInfo struct { } `json:"selfmenu_info"` } -//SelfMenuButton 自定义菜单配置详情 +// SelfMenuButton 自定义菜单配置详情 type SelfMenuButton struct { Type string `json:"type"` Name string `json:"name"` @@ -89,7 +89,7 @@ type SelfMenuButton struct { } `json:"news_info,omitempty"` } -//ButtonNew 图文消息菜单 +// ButtonNew 图文消息菜单 type ButtonNew struct { Title string `json:"title"` Author string `json:"author"` @@ -100,7 +100,7 @@ type ButtonNew struct { SourceURL string `json:"source_url"` } -//MatchRule 个性化菜单规则 +// MatchRule 个性化菜单规则 type MatchRule struct { GroupID string `json:"group_id,omitempty"` Sex string `json:"sex,omitempty"` @@ -111,14 +111,14 @@ type MatchRule struct { Language string `json:"language,omitempty"` } -//NewMenu 实例 +// NewMenu 实例 func NewMenu(context *context.Context) *Menu { menu := new(Menu) menu.Context = context return menu } -//SetMenu 设置按钮 +// SetMenu 设置按钮 func (menu *Menu) SetMenu(buttons []*Button) error { accessToken, err := menu.GetAccessToken() if err != nil { @@ -138,7 +138,7 @@ func (menu *Menu) SetMenu(buttons []*Button) error { return util.DecodeWithCommonError(response, "SetMenu") } -//SetMenuByJSON 设置按钮 +// SetMenuByJSON 设置按钮 func (menu *Menu) SetMenuByJSON(jsonInfo string) error { accessToken, err := menu.GetAccessToken() if err != nil { @@ -155,7 +155,7 @@ func (menu *Menu) SetMenuByJSON(jsonInfo string) error { return util.DecodeWithCommonError(response, "SetMenuByJSON") } -//GetMenu 获取菜单配置 +// GetMenu 获取菜单配置 func (menu *Menu) GetMenu() (resMenu ResMenu, err error) { var accessToken string accessToken, err = menu.GetAccessToken() @@ -179,7 +179,7 @@ func (menu *Menu) GetMenu() (resMenu ResMenu, err error) { return } -//DeleteMenu 删除菜单 +// DeleteMenu 删除菜单 func (menu *Menu) DeleteMenu() error { accessToken, err := menu.GetAccessToken() if err != nil { @@ -194,7 +194,7 @@ func (menu *Menu) DeleteMenu() error { return util.DecodeWithCommonError(response, "GetMenu") } -//AddConditional 添加个性化菜单 +// AddConditional 添加个性化菜单 func (menu *Menu) AddConditional(buttons []*Button, matchRule *MatchRule) error { accessToken, err := menu.GetAccessToken() if err != nil { @@ -215,7 +215,7 @@ func (menu *Menu) AddConditional(buttons []*Button, matchRule *MatchRule) error return util.DecodeWithCommonError(response, "AddConditional") } -//AddConditionalByJSON 添加个性化菜单 +// AddConditionalByJSON 添加个性化菜单 func (menu *Menu) AddConditionalByJSON(jsonInfo string) error { accessToken, err := menu.GetAccessToken() if err != nil { @@ -231,7 +231,7 @@ func (menu *Menu) AddConditionalByJSON(jsonInfo string) error { return util.DecodeWithCommonError(response, "AddConditional") } -//DeleteConditional 删除个性化菜单 +// DeleteConditional 删除个性化菜单 func (menu *Menu) DeleteConditional(menuID int64) error { accessToken, err := menu.GetAccessToken() if err != nil { @@ -251,7 +251,7 @@ func (menu *Menu) DeleteConditional(menuID int64) error { return util.DecodeWithCommonError(response, "DeleteConditional") } -//MenuTryMatch 菜单匹配 +// MenuTryMatch 菜单匹配 func (menu *Menu) MenuTryMatch(userID string) (buttons []Button, err error) { var accessToken string accessToken, err = menu.GetAccessToken() @@ -278,7 +278,7 @@ func (menu *Menu) MenuTryMatch(userID string) (buttons []Button, err error) { return } -//GetCurrentSelfMenuInfo 获取自定义菜单配置接口 +// GetCurrentSelfMenuInfo 获取自定义菜单配置接口 func (menu *Menu) GetCurrentSelfMenuInfo() (resSelfMenuInfo ResSelfMenuInfo, err error) { var accessToken string accessToken, err = menu.GetAccessToken() diff --git a/officialaccount/message/customer_message.go b/officialaccount/message/customer_message.go index 9c64cb0..67acc8a 100644 --- a/officialaccount/message/customer_message.go +++ b/officialaccount/message/customer_message.go @@ -12,35 +12,35 @@ const ( customerSendMessage = "https://api.weixin.qq.com/cgi-bin/message/custom/send" ) -//Manager 消息管理者,可以发送消息 +// Manager 消息管理者,可以发送消息 type Manager struct { *context.Context } -//NewMessageManager 实例化消息管理者 +// NewMessageManager 实例化消息管理者 func NewMessageManager(context *context.Context) *Manager { return &Manager{ context, } } -//CustomerMessage 客服消息 +// CustomerMessage 客服消息 type CustomerMessage struct { - ToUser string `json:"touser"` //接受者OpenID - Msgtype MsgType `json:"msgtype"` //客服消息类型 - Text *MediaText `json:"text,omitempty"` //可选 - Image *MediaResource `json:"image,omitempty"` //可选 - Voice *MediaResource `json:"voice,omitempty"` //可选 - Video *MediaVideo `json:"video,omitempty"` //可选 - Music *MediaMusic `json:"music,omitempty"` //可选 - News *MediaNews `json:"news,omitempty"` //可选 - Mpnews *MediaResource `json:"mpnews,omitempty"` //可选 - Wxcard *MediaWxcard `json:"wxcard,omitempty"` //可选 - Msgmenu *MediaMsgmenu `json:"msgmenu,omitempty"` //可选 - Miniprogrampage *MediaMiniprogrampage `json:"miniprogrampage,omitempty"` //可选 + ToUser string `json:"touser"` // 接受者OpenID + Msgtype MsgType `json:"msgtype"` // 客服消息类型 + Text *MediaText `json:"text,omitempty"` // 可选 + Image *MediaResource `json:"image,omitempty"` // 可选 + Voice *MediaResource `json:"voice,omitempty"` // 可选 + Video *MediaVideo `json:"video,omitempty"` // 可选 + Music *MediaMusic `json:"music,omitempty"` // 可选 + News *MediaNews `json:"news,omitempty"` // 可选 + Mpnews *MediaResource `json:"mpnews,omitempty"` // 可选 + Wxcard *MediaWxcard `json:"wxcard,omitempty"` // 可选 + Msgmenu *MediaMsgmenu `json:"msgmenu,omitempty"` // 可选 + Miniprogrampage *MediaMiniprogrampage `json:"miniprogrampage,omitempty"` // 可选 } -//NewCustomerTextMessage 文本消息结构体构造方法 +// NewCustomerTextMessage 文本消息结构体构造方法 func NewCustomerTextMessage(toUser, text string) *CustomerMessage { return &CustomerMessage{ ToUser: toUser, @@ -51,7 +51,7 @@ func NewCustomerTextMessage(toUser, text string) *CustomerMessage { } } -//NewCustomerImgMessage 图片消息的构造方法 +// NewCustomerImgMessage 图片消息的构造方法 func NewCustomerImgMessage(toUser, mediaID string) *CustomerMessage { return &CustomerMessage{ ToUser: toUser, @@ -62,7 +62,7 @@ func NewCustomerImgMessage(toUser, mediaID string) *CustomerMessage { } } -//NewCustomerVoiceMessage 语音消息的构造方法 +// NewCustomerVoiceMessage 语音消息的构造方法 func NewCustomerVoiceMessage(toUser, mediaID string) *CustomerMessage { return &CustomerMessage{ ToUser: toUser, @@ -73,7 +73,7 @@ func NewCustomerVoiceMessage(toUser, mediaID string) *CustomerMessage { } } -//NewCustomerMiniprogrampageMessage 小程序卡片消息的构造方法 +// NewCustomerMiniprogrampageMessage 小程序卡片消息的构造方法 func NewCustomerMiniprogrampageMessage(toUser, title, appID, pagePath, thumbMediaID string) *CustomerMessage { return &CustomerMessage{ ToUser: toUser, @@ -87,17 +87,17 @@ func NewCustomerMiniprogrampageMessage(toUser, title, appID, pagePath, thumbMedi } } -//MediaText 文本消息的文字 +// MediaText 文本消息的文字 type MediaText struct { Content string `json:"content"` } -//MediaResource 消息使用的永久素材id +// MediaResource 消息使用的永久素材id type MediaResource struct { MediaID string `json:"media_id"` } -//MediaVideo 视频消息包含的内容 +// MediaVideo 视频消息包含的内容 type MediaVideo struct { MediaID string `json:"media_id"` ThumbMediaID string `json:"thumb_media_id"` @@ -105,7 +105,7 @@ type MediaVideo struct { Description string `json:"description"` } -//MediaMusic 音乐消息包括的内容 +// MediaMusic 音乐消息包括的内容 type MediaMusic struct { Title string `json:"title"` Description string `json:"description"` @@ -114,12 +114,12 @@ type MediaMusic struct { ThumbMediaID string `json:"thumb_media_id"` } -//MediaNews 图文消息的内容 +// MediaNews 图文消息的内容 type MediaNews struct { Articles []MediaArticles `json:"articles"` } -//MediaArticles 图文消息的内容的文章列表中的单独一条 +// MediaArticles 图文消息的内容的文章列表中的单独一条 type MediaArticles struct { Title string `json:"title"` Description string `json:"description"` @@ -127,25 +127,25 @@ type MediaArticles struct { Picurl string `json:"picurl"` } -//MediaMsgmenu 菜单消息的内容 +// MediaMsgmenu 菜单消息的内容 type MediaMsgmenu struct { HeadContent string `json:"head_content"` List []MsgmenuItem `json:"list"` TailContent string `json:"tail_content"` } -//MsgmenuItem 菜单消息的菜单按钮 +// MsgmenuItem 菜单消息的菜单按钮 type MsgmenuItem struct { ID string `json:"id"` Content string `json:"content"` } -//MediaWxcard 卡券的id +// MediaWxcard 卡券的id type MediaWxcard struct { CardID string `json:"card_id"` } -//MediaMiniprogrampage 小程序消息 +// MediaMiniprogrampage 小程序消息 type MediaMiniprogrampage struct { Title string `json:"title"` AppID string `json:"appid"` @@ -153,7 +153,7 @@ type MediaMiniprogrampage struct { ThumbMediaID string `json:"thumb_media_id"` } -//Send 发送客服消息 +// Send 发送客服消息 func (manager *Manager) Send(msg *CustomerMessage) error { accessToken, err := manager.Context.GetAccessToken() if err != nil { diff --git a/officialaccount/message/image.go b/officialaccount/message/image.go index 93e6bc0..b79f9a4 100644 --- a/officialaccount/message/image.go +++ b/officialaccount/message/image.go @@ -1,6 +1,6 @@ package message -//Image 图片消息 +// Image 图片消息 type Image struct { CommonToken @@ -9,7 +9,7 @@ type Image struct { } `xml:"Image"` } -//NewImage 回复图片消息 +// NewImage 回复图片消息 func NewImage(mediaID string) *Image { image := new(Image) image.Image.MediaID = mediaID diff --git a/officialaccount/message/message.go b/officialaccount/message/message.go index ecbe12a..9a5b659 100644 --- a/officialaccount/message/message.go +++ b/officialaccount/message/message.go @@ -16,67 +16,67 @@ type EventType string type InfoType string const ( - //MsgTypeText 表示文本消息 + // MsgTypeText 表示文本消息 MsgTypeText MsgType = "text" - //MsgTypeImage 表示图片消息 + // MsgTypeImage 表示图片消息 MsgTypeImage = "image" - //MsgTypeVoice 表示语音消息 + // MsgTypeVoice 表示语音消息 MsgTypeVoice = "voice" - //MsgTypeVideo 表示视频消息 + // MsgTypeVideo 表示视频消息 MsgTypeVideo = "video" - //MsgTypeMiniprogrampage 表示小程序卡片消息 + // MsgTypeMiniprogrampage 表示小程序卡片消息 MsgTypeMiniprogrampage = "miniprogrampage" - //MsgTypeShortVideo 表示短视频消息[限接收] + // MsgTypeShortVideo 表示短视频消息[限接收] MsgTypeShortVideo = "shortvideo" - //MsgTypeLocation 表示坐标消息[限接收] + // MsgTypeLocation 表示坐标消息[限接收] MsgTypeLocation = "location" - //MsgTypeLink 表示链接消息[限接收] + // MsgTypeLink 表示链接消息[限接收] MsgTypeLink = "link" - //MsgTypeMusic 表示音乐消息[限回复] + // MsgTypeMusic 表示音乐消息[限回复] MsgTypeMusic = "music" - //MsgTypeNews 表示图文消息[限回复] + // MsgTypeNews 表示图文消息[限回复] MsgTypeNews = "news" - //MsgTypeTransfer 表示消息消息转发到客服 + // MsgTypeTransfer 表示消息消息转发到客服 MsgTypeTransfer = "transfer_customer_service" - //MsgTypeEvent 表示事件推送消息 + // MsgTypeEvent 表示事件推送消息 MsgTypeEvent = "event" ) const ( - //EventSubscribe 订阅 + // EventSubscribe 订阅 EventSubscribe EventType = "subscribe" - //EventUnsubscribe 取消订阅 + // EventUnsubscribe 取消订阅 EventUnsubscribe = "unsubscribe" - //EventScan 用户已经关注公众号,则微信会将带场景值扫描事件推送给开发者 + // EventScan 用户已经关注公众号,则微信会将带场景值扫描事件推送给开发者 EventScan = "SCAN" - //EventLocation 上报地理位置事件 + // EventLocation 上报地理位置事件 EventLocation = "LOCATION" - //EventClick 点击菜单拉取消息时的事件推送 + // EventClick 点击菜单拉取消息时的事件推送 EventClick = "CLICK" - //EventView 点击菜单跳转链接时的事件推送 + // EventView 点击菜单跳转链接时的事件推送 EventView = "VIEW" - //EventScancodePush 扫码推事件的事件推送 + // EventScancodePush 扫码推事件的事件推送 EventScancodePush = "scancode_push" - //EventScancodeWaitmsg 扫码推事件且弹出“消息接收中”提示框的事件推送 + // EventScancodeWaitmsg 扫码推事件且弹出“消息接收中”提示框的事件推送 EventScancodeWaitmsg = "scancode_waitmsg" - //EventPicSysphoto 弹出系统拍照发图的事件推送 + // EventPicSysphoto 弹出系统拍照发图的事件推送 EventPicSysphoto = "pic_sysphoto" - //EventPicPhotoOrAlbum 弹出拍照或者相册发图的事件推送 + // EventPicPhotoOrAlbum 弹出拍照或者相册发图的事件推送 EventPicPhotoOrAlbum = "pic_photo_or_album" - //EventPicWeixin 弹出微信相册发图器的事件推送 + // EventPicWeixin 弹出微信相册发图器的事件推送 EventPicWeixin = "pic_weixin" - //EventLocationSelect 弹出地理位置选择器的事件推送 + // EventLocationSelect 弹出地理位置选择器的事件推送 EventLocationSelect = "location_select" - //EventTemplateSendJobFinish 发送模板消息推送通知 + // EventTemplateSendJobFinish 发送模板消息推送通知 EventTemplateSendJobFinish = "TEMPLATESENDJOBFINISH" - //EventMassSendJobFinish 群发消息推送通知 + // EventMassSendJobFinish 群发消息推送通知 EventMassSendJobFinish = "MASSSENDJOBFINISH" - //EventWxaMediaCheck 异步校验图片/音频是否含有违法违规内容推送事件 + // EventWxaMediaCheck 异步校验图片/音频是否含有违法违规内容推送事件 EventWxaMediaCheck = "wxa_media_check" ) const ( - //微信开放平台需要用到 + // 微信开放平台需要用到 // InfoTypeVerifyTicket 返回ticket InfoTypeVerifyTicket InfoType = "component_verify_ticket" @@ -88,13 +88,13 @@ const ( InfoTypeUpdateAuthorized = "updateauthorized" ) -//MixMessage 存放所有微信发送过来的消息和事件 +// MixMessage 存放所有微信发送过来的消息和事件 type MixMessage struct { CommonToken - //基本消息 - MsgID int64 `xml:"MsgId"` //其他消息推送过来是MsgId - TemplateMsgID int64 `xml:"MsgID"` //模板消息推送成功的消息是MsgID + // 基本消息 + MsgID int64 `xml:"MsgId"` // 其他消息推送过来是MsgId + TemplateMsgID int64 `xml:"MsgID"` // 模板消息推送成功的消息是MsgID Content string `xml:"Content"` Recognition string `xml:"Recognition"` PicURL string `xml:"PicUrl"` @@ -109,7 +109,7 @@ type MixMessage struct { Description string `xml:"Description"` URL string `xml:"Url"` - //事件相关 + // 事件相关 Event EventType `xml:"Event"` EventKey string `xml:"EventKey"` Ticket string `xml:"Ticket"` @@ -168,23 +168,23 @@ type MixMessage struct { TraceID string `xml:"trace_id"` StatusCode int `xml:"status_code"` - //设备相关 + // 设备相关 device.MsgDevice } -//EventPic 发图事件推送 +// EventPic 发图事件推送 type EventPic struct { PicMd5Sum string `xml:"PicMd5Sum"` } -//EncryptedXMLMsg 安全模式下的消息体 +// EncryptedXMLMsg 安全模式下的消息体 type EncryptedXMLMsg struct { XMLName struct{} `xml:"xml" json:"-"` ToUserName string `xml:"ToUserName" json:"ToUserName"` EncryptedMsg string `xml:"Encrypt" json:"Encrypt"` } -//ResponseEncryptedXMLMsg 需要返回的消息体 +// ResponseEncryptedXMLMsg 需要返回的消息体 type ResponseEncryptedXMLMsg struct { XMLName struct{} `xml:"xml" json:"-"` EncryptedMsg string `xml:"Encrypt" json:"Encrypt"` @@ -212,27 +212,27 @@ type CommonToken struct { MsgType MsgType `xml:"MsgType"` } -//SetToUserName set ToUserName +// SetToUserName set ToUserName func (msg *CommonToken) SetToUserName(toUserName CDATA) { msg.ToUserName = toUserName } -//SetFromUserName set FromUserName +// SetFromUserName set FromUserName func (msg *CommonToken) SetFromUserName(fromUserName CDATA) { msg.FromUserName = fromUserName } -//SetCreateTime set createTime +// SetCreateTime set createTime func (msg *CommonToken) SetCreateTime(createTime int64) { msg.CreateTime = createTime } -//SetMsgType set MsgType +// SetMsgType set MsgType func (msg *CommonToken) SetMsgType(msgType MsgType) { msg.MsgType = msgType } -//GetOpenID get the FromUserName value +// GetOpenID get the FromUserName value func (msg *CommonToken) GetOpenID() string { return string(msg.FromUserName) } diff --git a/officialaccount/message/music.go b/officialaccount/message/music.go index 3e010ed..5d71f5a 100644 --- a/officialaccount/message/music.go +++ b/officialaccount/message/music.go @@ -1,6 +1,6 @@ package message -//Music 音乐消息 +// Music 音乐消息 type Music struct { CommonToken @@ -13,7 +13,7 @@ type Music struct { } `xml:"Music"` } -//NewMusic 回复音乐消息 +// NewMusic 回复音乐消息 func NewMusic(title, description, musicURL, hQMusicURL, thumbMediaID string) *Music { music := new(Music) music.Music.Title = title diff --git a/officialaccount/message/news.go b/officialaccount/message/news.go index ee28b0c..fa00249 100644 --- a/officialaccount/message/news.go +++ b/officialaccount/message/news.go @@ -1,6 +1,6 @@ package message -//News 图文消息 +// News 图文消息 type News struct { CommonToken @@ -8,7 +8,7 @@ type News struct { Articles []*Article `xml:"Articles>item,omitempty"` } -//NewNews 初始化图文消息 +// NewNews 初始化图文消息 func NewNews(articles []*Article) *News { news := new(News) news.ArticleCount = len(articles) @@ -16,7 +16,7 @@ func NewNews(articles []*Article) *News { return news } -//Article 单篇文章 +// Article 单篇文章 type Article struct { Title string `xml:"Title,omitempty"` Description string `xml:"Description,omitempty"` @@ -24,7 +24,7 @@ type Article struct { URL string `xml:"Url,omitempty"` } -//NewArticle 初始化文章 +// NewArticle 初始化文章 func NewArticle(title, description, picURL, url string) *Article { article := new(Article) article.Title = title diff --git a/officialaccount/message/reply.go b/officialaccount/message/reply.go index 53592f0..5488fb8 100644 --- a/officialaccount/message/reply.go +++ b/officialaccount/message/reply.go @@ -2,13 +2,13 @@ package message import "errors" -//ErrInvalidReply 无效的回复 +// ErrInvalidReply 无效的回复 var ErrInvalidReply = errors.New("无效的回复消息") -//ErrUnsupportReply 不支持的回复类型 +// ErrUnsupportReply 不支持的回复类型 var ErrUnsupportReply = errors.New("不支持的回复消息") -//Reply 消息回复 +// Reply 消息回复 type Reply struct { MsgType MsgType MsgData interface{} diff --git a/officialaccount/message/subscribe.go b/officialaccount/message/subscribe.go index 3f9a42e..44fd10b 100644 --- a/officialaccount/message/subscribe.go +++ b/officialaccount/message/subscribe.go @@ -14,36 +14,36 @@ const ( subscribeTemplateDelURL = "https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate" ) -//Subscribe 订阅消息 +// Subscribe 订阅消息 type Subscribe struct { *context.Context } -//NewSubscribe 实例化 +// NewSubscribe 实例化 func NewSubscribe(context *context.Context) *Subscribe { tpl := new(Subscribe) tpl.Context = context return tpl } -//SubscribeMessage 发送的订阅消息内容 +// SubscribeMessage 发送的订阅消息内容 type SubscribeMessage struct { ToUser string `json:"touser"` // 必须, 接受者OpenID TemplateID string `json:"template_id"` // 必须, 模版ID Page string `json:"page,omitempty"` // 可选, 跳转网页时填写 Data map[string]*SubscribeDataItem `json:"data"` // 必须, 模板数据 MiniProgram struct { - AppID string `json:"appid"` //所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系) - PagePath string `json:"pagepath"` //所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar) - } `json:"miniprogram"` //可选,跳转至小程序地址 + AppID string `json:"appid"` // 所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系) + PagePath string `json:"pagepath"` // 所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar) + } `json:"miniprogram"` // 可选,跳转至小程序地址 } -//SubscribeDataItem 模版内某个 .DATA 的值 +// SubscribeDataItem 模版内某个 .DATA 的值 type SubscribeDataItem struct { Value string `json:"value"` } -//Send 发送订阅消息 +// Send 发送订阅消息 func (tpl *Subscribe) Send(msg *SubscribeMessage) (err error) { var accessToken string accessToken, err = tpl.GetAccessToken() @@ -61,10 +61,10 @@ func (tpl *Subscribe) Send(msg *SubscribeMessage) (err error) { // PrivateSubscribeItem 私有订阅消息模板 type PrivateSubscribeItem struct { PriTmplID string `json:"priTmplId"` // 添加至帐号下的模板 id,发送订阅通知时所需 - Title string `json:"title"` //模版标题 - Content string `json:"content"` //模版内容 - Example string `json:"example"` //模板内容示例 - SubType int `json:"type"` //模版类型,2 为一次性订阅,3 为长期订阅 + Title string `json:"title"` // 模版标题 + Content string `json:"content"` // 模版内容 + Example string `json:"example"` // 模板内容示例 + SubType int `json:"type"` // 模版类型,2 为一次性订阅,3 为长期订阅 } type resPrivateSubscribeList struct { @@ -72,7 +72,7 @@ type resPrivateSubscribeList struct { SubscriptionList []*PrivateSubscribeItem `json:"data"` } -//List 获取私有订阅消息模板列表 +// List 获取私有订阅消息模板列表 func (tpl *Subscribe) List() (templateList []*PrivateSubscribeItem, err error) { var accessToken string accessToken, err = tpl.GetAccessToken() diff --git a/officialaccount/message/template.go b/officialaccount/message/template.go index 8cda602..79e2e05 100644 --- a/officialaccount/message/template.go +++ b/officialaccount/message/template.go @@ -15,19 +15,19 @@ const ( templateDelURL = "https://api.weixin.qq.com/cgi-bin/template/del_private_template" ) -//Template 模板消息 +// Template 模板消息 type Template struct { *context.Context } -//NewTemplate 实例化 +// NewTemplate 实例化 func NewTemplate(context *context.Context) *Template { tpl := new(Template) tpl.Context = context return tpl } -//TemplateMessage 发送的模板消息内容 +// TemplateMessage 发送的模板消息内容 type TemplateMessage struct { ToUser string `json:"touser"` // 必须, 接受者OpenID TemplateID string `json:"template_id"` // 必须, 模版ID @@ -36,12 +36,12 @@ type TemplateMessage struct { Data map[string]*TemplateDataItem `json:"data"` // 必须, 模板数据 MiniProgram struct { - AppID string `json:"appid"` //所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系) - PagePath string `json:"pagepath"` //所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar) - } `json:"miniprogram"` //可选,跳转至小程序地址 + AppID string `json:"appid"` // 所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系) + PagePath string `json:"pagepath"` // 所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar) + } `json:"miniprogram"` // 可选,跳转至小程序地址 } -//TemplateDataItem 模版内某个 .DATA 的值 +// TemplateDataItem 模版内某个 .DATA 的值 type TemplateDataItem struct { Value string `json:"value"` Color string `json:"color,omitempty"` @@ -53,7 +53,7 @@ type resTemplateSend struct { MsgID int64 `json:"msgid"` } -//Send 发送模板消息 +// Send 发送模板消息 func (tpl *Template) Send(msg *TemplateMessage) (msgID int64, err error) { var accessToken string accessToken, err = tpl.GetAccessToken() @@ -95,7 +95,7 @@ type resTemplateList struct { TemplateList []*TemplateItem `json:"template_list"` } -//List 获取模板列表 +// List 获取模板列表 func (tpl *Template) List() (templateList []*TemplateItem, err error) { var accessToken string accessToken, err = tpl.GetAccessToken() diff --git a/officialaccount/message/text.go b/officialaccount/message/text.go index 88ac19a..a6819d9 100644 --- a/officialaccount/message/text.go +++ b/officialaccount/message/text.go @@ -1,12 +1,12 @@ package message -//Text 文本消息 +// Text 文本消息 type Text struct { CommonToken Content CDATA `xml:"Content"` } -//NewText 初始化文本消息 +// NewText 初始化文本消息 func NewText(content string) *Text { text := new(Text) text.Content = CDATA(content) diff --git a/officialaccount/message/transfer_customer.go b/officialaccount/message/transfer_customer.go index af336e8..7dbf9b7 100644 --- a/officialaccount/message/transfer_customer.go +++ b/officialaccount/message/transfer_customer.go @@ -1,18 +1,18 @@ package message -//TransferCustomer 转发客服消息 +// TransferCustomer 转发客服消息 type TransferCustomer struct { CommonToken TransInfo *TransInfo `xml:"TransInfo,omitempty"` } -//TransInfo 转发到指定客服 +// TransInfo 转发到指定客服 type TransInfo struct { KfAccount string `xml:"KfAccount"` } -//NewTransferCustomer 实例化 +// NewTransferCustomer 实例化 func NewTransferCustomer(kfAccount string) *TransferCustomer { tc := new(TransferCustomer) if kfAccount != "" { diff --git a/officialaccount/message/video.go b/officialaccount/message/video.go index a082065..6f64875 100644 --- a/officialaccount/message/video.go +++ b/officialaccount/message/video.go @@ -1,6 +1,6 @@ package message -//Video 视频消息 +// Video 视频消息 type Video struct { CommonToken @@ -11,7 +11,7 @@ type Video struct { } `xml:"Video"` } -//NewVideo 回复图片消息 +// NewVideo 回复图片消息 func NewVideo(mediaID, title, description string) *Video { video := new(Video) video.Video.MediaID = mediaID diff --git a/officialaccount/message/voice.go b/officialaccount/message/voice.go index d76985c..a9cb662 100644 --- a/officialaccount/message/voice.go +++ b/officialaccount/message/voice.go @@ -1,6 +1,6 @@ package message -//Voice 语音消息 +// Voice 语音消息 type Voice struct { CommonToken @@ -9,7 +9,7 @@ type Voice struct { } `xml:"Voice"` } -//NewVoice 回复语音消息 +// NewVoice 回复语音消息 func NewVoice(mediaID string) *Voice { voice := new(Voice) voice.Voice.MediaID = mediaID diff --git a/officialaccount/oauth/oauth.go b/officialaccount/oauth/oauth.go index 27dde91..385fe9b 100644 --- a/officialaccount/oauth/oauth.go +++ b/officialaccount/oauth/oauth.go @@ -19,32 +19,32 @@ const ( checkAccessTokenURL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s" ) -//Oauth 保存用户授权信息 +// Oauth 保存用户授权信息 type Oauth struct { *context.Context } -//NewOauth 实例化授权信息 +// NewOauth 实例化授权信息 func NewOauth(context *context.Context) *Oauth { auth := new(Oauth) auth.Context = context return auth } -//GetRedirectURL 获取跳转的url地址 +// GetRedirectURL 获取跳转的url地址 func (oauth *Oauth) GetRedirectURL(redirectURI, scope, state string) (string, error) { - //url encode + // url encode urlStr := url.QueryEscape(redirectURI) return fmt.Sprintf(redirectOauthURL, oauth.AppID, urlStr, scope, state), nil } -//GetWebAppRedirectURL 获取网页应用跳转的url地址 +// GetWebAppRedirectURL 获取网页应用跳转的url地址 func (oauth *Oauth) GetWebAppRedirectURL(redirectURI, scope, state string) (string, error) { urlStr := url.QueryEscape(redirectURI) return fmt.Sprintf(webAppRedirectOauthURL, oauth.AppID, urlStr, scope, state), nil } -//Redirect 跳转到网页授权 +// Redirect 跳转到网页授权 func (oauth *Oauth) Redirect(writer http.ResponseWriter, req *http.Request, redirectURI, scope, state string) error { location, err := oauth.GetRedirectURL(redirectURI, scope, state) if err != nil { @@ -88,7 +88,7 @@ func (oauth *Oauth) GetUserAccessToken(code string) (result ResAccessToken, err return } -//RefreshAccessToken 刷新access_token +// RefreshAccessToken 刷新access_token func (oauth *Oauth) RefreshAccessToken(refreshToken string) (result ResAccessToken, err error) { urlStr := fmt.Sprintf(refreshAccessTokenURL, oauth.AppID, refreshToken) var response []byte @@ -107,7 +107,7 @@ func (oauth *Oauth) RefreshAccessToken(refreshToken string) (result ResAccessTok return } -//CheckAccessToken 检验access_token是否有效 +// CheckAccessToken 检验access_token是否有效 func (oauth *Oauth) CheckAccessToken(accessToken, openID string) (b bool, err error) { urlStr := fmt.Sprintf(checkAccessTokenURL, accessToken, openID) var response []byte @@ -128,7 +128,7 @@ func (oauth *Oauth) CheckAccessToken(accessToken, openID string) (b bool, err er return } -//UserInfo 用户授权获取到用户信息 +// UserInfo 用户授权获取到用户信息 type UserInfo struct { util.CommonError @@ -143,7 +143,7 @@ type UserInfo struct { Unionid string `json:"unionid"` } -//GetUserInfo 如果scope为 snsapi_userinfo 则可以通过此方法获取到用户基本信息 +// GetUserInfo 如果scope为 snsapi_userinfo 则可以通过此方法获取到用户基本信息 func (oauth *Oauth) GetUserInfo(accessToken, openID, lang string) (result UserInfo, err error) { if lang == "" { lang = "zh_CN" diff --git a/officialaccount/ocr/ocr.go b/officialaccount/ocr/ocr.go index c1521f8..471d87f 100644 --- a/officialaccount/ocr/ocr.go +++ b/officialaccount/ocr/ocr.go @@ -18,18 +18,18 @@ const ( ocrPlateNumberURL = "https://api.weixin.qq.com/cv/ocr/platenum" ) -//OCR struct +// OCR struct type OCR struct { *context.Context } -//coordinate 坐标 +// coordinate 坐标 type coordinate struct { X int64 `json:"x,omitempty"` Y int64 `json:"y,omitempty"` } -//position 位置 +// position 位置 type position struct { LeftTop coordinate `json:"left_top"` RightTop coordinate `json:"right_top"` @@ -37,13 +37,13 @@ type position struct { LeftBottom coordinate `json:"left_bottom"` } -//imageSize 图片尺寸 +// imageSize 图片尺寸 type imageSize struct { Width int64 `json:"w,omitempty"` Height int64 `json:"h,omitempty"` } -//ResDriving 行驶证返回结果 +// ResDriving 行驶证返回结果 type ResDriving struct { util.CommonError @@ -68,7 +68,7 @@ type ResDriving struct { ImageSize imageSize `json:"img_size,omitempty"` } -//ResIDCard 身份证返回结果 +// ResIDCard 身份证返回结果 type ResIDCard struct { util.CommonError @@ -81,14 +81,14 @@ type ResIDCard struct { ValidDate string `json:"valid_date,omitempty"` } -//ResBankCard 银行卡返回结果 +// ResBankCard 银行卡返回结果 type ResBankCard struct { util.CommonError Number string `json:"number,omitempty"` } -//ResDrivingLicense 驾驶证返回结果 +// ResDrivingLicense 驾驶证返回结果 type ResDrivingLicense struct { util.CommonError @@ -105,7 +105,7 @@ type ResDrivingLicense struct { OfficialSeal string `json:"official_seal,omitempty"` } -//ResBizLicense 营业执照返回结果 +// ResBizLicense 营业执照返回结果 type ResBizLicense struct { util.CommonError @@ -125,7 +125,7 @@ type ResBizLicense struct { ImageSize imageSize `json:"img_size,omitempty"` } -//ResCommon 公共印刷品返回结果 +// ResCommon 公共印刷品返回结果 type ResCommon struct { util.CommonError @@ -133,27 +133,27 @@ type ResCommon struct { ImageSize imageSize `json:"img_size,omitempty"` } -//commonItem 公共元素 +// commonItem 公共元素 type commonItem struct { Position position `json:"pos"` Text string `json:"text"` } -//ResPlateNumber 车牌号返回结果 +// ResPlateNumber 车牌号返回结果 type ResPlateNumber struct { util.CommonError Number string `json:"number"` } -//NewOCR 实例 +// NewOCR 实例 func NewOCR(c *context.Context) *OCR { ocr := new(OCR) ocr.Context = c return ocr } -//IDCard 身份证OCR识别接口 +// IDCard 身份证OCR识别接口 func (ocr *OCR) IDCard(path string) (ResIDCard ResIDCard, err error) { accessToken, err := ocr.GetAccessToken() if err != nil { @@ -172,7 +172,7 @@ func (ocr *OCR) IDCard(path string) (ResIDCard ResIDCard, err error) { return } -//BankCard 银行卡OCR识别接口 +// BankCard 银行卡OCR识别接口 func (ocr *OCR) BankCard(path string) (ResBankCard ResBankCard, err error) { accessToken, err := ocr.GetAccessToken() if err != nil { @@ -191,7 +191,7 @@ func (ocr *OCR) BankCard(path string) (ResBankCard ResBankCard, err error) { return } -//Driving 行驶证OCR识别接口 +// Driving 行驶证OCR识别接口 func (ocr *OCR) Driving(path string) (ResDriving ResDriving, err error) { accessToken, err := ocr.GetAccessToken() if err != nil { @@ -210,7 +210,7 @@ func (ocr *OCR) Driving(path string) (ResDriving ResDriving, err error) { return } -//DrivingLicense 驾驶证OCR识别接口 +// DrivingLicense 驾驶证OCR识别接口 func (ocr *OCR) DrivingLicense(path string) (ResDrivingLicense ResDrivingLicense, err error) { accessToken, err := ocr.GetAccessToken() if err != nil { @@ -229,7 +229,7 @@ func (ocr *OCR) DrivingLicense(path string) (ResDrivingLicense ResDrivingLicense return } -//BizLicense 营业执照OCR识别接口 +// BizLicense 营业执照OCR识别接口 func (ocr *OCR) BizLicense(path string) (ResBizLicense ResBizLicense, err error) { accessToken, err := ocr.GetAccessToken() if err != nil { @@ -248,7 +248,7 @@ func (ocr *OCR) BizLicense(path string) (ResBizLicense ResBizLicense, err error) return } -//Common 通用印刷体OCR识别接口 +// Common 通用印刷体OCR识别接口 func (ocr *OCR) Common(path string) (ResCommon ResCommon, err error) { accessToken, err := ocr.GetAccessToken() if err != nil { @@ -267,7 +267,7 @@ func (ocr *OCR) Common(path string) (ResCommon ResCommon, err error) { return } -//PlateNumber 车牌OCR识别接口 +// PlateNumber 车牌OCR识别接口 func (ocr *OCR) PlateNumber(path string) (ResPlateNumber ResPlateNumber, err error) { accessToken, err := ocr.GetAccessToken() if err != nil { diff --git a/officialaccount/officialaccount.go b/officialaccount/officialaccount.go index 7cc40ec..5697312 100644 --- a/officialaccount/officialaccount.go +++ b/officialaccount/officialaccount.go @@ -22,12 +22,12 @@ import ( "github.com/silenceper/wechat/v2/officialaccount/user" ) -//OfficialAccount 微信公众号相关API +// OfficialAccount 微信公众号相关API type OfficialAccount struct { ctx *context.Context } -//NewOfficialAccount 实例化公众号API +// NewOfficialAccount 实例化公众号API func NewOfficialAccount(cfg *config.Config) *OfficialAccount { defaultAkHandle := credential.NewDefaultAccessToken(cfg.AppID, cfg.AppSecret, credential.CacheKeyOfficialAccountPrefix, cfg.Cache) ctx := &context.Context{ @@ -37,7 +37,7 @@ func NewOfficialAccount(cfg *config.Config) *OfficialAccount { return &OfficialAccount{ctx: ctx} } -//SetAccessTokenHandle 自定义access_token获取方式 +// SetAccessTokenHandle 自定义access_token获取方式 func (officialAccount *OfficialAccount) SetAccessTokenHandle(accessTokenHandle credential.AccessTokenHandle) { officialAccount.ctx.AccessTokenHandle = accessTokenHandle } @@ -65,7 +65,7 @@ func (officialAccount *OfficialAccount) GetServer(req *http.Request, writer http return srv } -//GetAccessToken 获取access_token +// GetAccessToken 获取access_token func (officialAccount *OfficialAccount) GetAccessToken() (string, error) { return officialAccount.ctx.GetAccessToken() } @@ -105,23 +105,23 @@ func (officialAccount *OfficialAccount) GetDevice() *device.Device { return device.NewDevice(officialAccount.ctx) } -//GetBroadcast 群发消息 -//TODO 待完善 +// GetBroadcast 群发消息 +// TODO 待完善 func (officialAccount *OfficialAccount) GetBroadcast() *broadcast.Broadcast { return broadcast.NewBroadcast(officialAccount.ctx) } -//GetDataCube 数据统计 +// GetDataCube 数据统计 func (officialAccount *OfficialAccount) GetDataCube() *datacube.DataCube { return datacube.NewCube(officialAccount.ctx) } -//GetOCR OCR接口 +// GetOCR OCR接口 func (officialAccount *OfficialAccount) GetOCR() *ocr.OCR { return ocr.NewOCR(officialAccount.ctx) } -//GetSubscribe 公众号订阅消息 +// GetSubscribe 公众号订阅消息 func (officialAccount *OfficialAccount) GetSubscribe() *message.Subscribe { return message.NewSubscribe(officialAccount.ctx) } diff --git a/officialaccount/server/server.go b/officialaccount/server/server.go index 9436b7e..c21b735 100644 --- a/officialaccount/server/server.go +++ b/officialaccount/server/server.go @@ -17,7 +17,7 @@ import ( "github.com/silenceper/wechat/v2/util" ) -//Server struct +// Server struct type Server struct { *context.Context Writer http.ResponseWriter @@ -40,7 +40,7 @@ type Server struct { timestamp int64 } -//NewServer init +// NewServer init func NewServer(context *context.Context) *Server { srv := new(Server) srv.Context = context @@ -52,7 +52,7 @@ func (srv *Server) SkipValidate(skip bool) { srv.skipValidate = skip } -//Serve 处理微信的请求消息 +// Serve 处理微信的请求消息 func (srv *Server) Serve() error { if !srv.Validate() { log.Error("Validate Signature Failed.") @@ -70,13 +70,13 @@ func (srv *Server) Serve() error { return err } - //debug print request msg + // debug print request msg log.Debugf("request msg =%s", string(srv.RequestRawXMLMsg)) return srv.buildResponse(response) } -//Validate 校验请求是否合法 +// Validate 校验请求是否合法 func (srv *Server) Validate() bool { if srv.skipValidate { return true @@ -88,16 +88,16 @@ func (srv *Server) Validate() bool { return signature == util.Signature(srv.Token, timestamp, nonce) } -//HandleRequest 处理微信的请求 +// HandleRequest 处理微信的请求 func (srv *Server) handleRequest() (reply *message.Reply, err error) { - //set isSafeMode + // set isSafeMode srv.isSafeMode = false encryptType := srv.Query("encrypt_type") if encryptType == "aes" { srv.isSafeMode = true } - //set openID + // set openID srv.openID = srv.Query("openid") var msg interface{} @@ -114,12 +114,12 @@ func (srv *Server) handleRequest() (reply *message.Reply, err error) { return } -//GetOpenID return openID +// GetOpenID return openID func (srv *Server) GetOpenID() string { return srv.openID } -//getMessage 解析微信返回的消息 +// getMessage 解析微信返回的消息 func (srv *Server) getMessage() (interface{}, error) { var rawXMLMsgBytes []byte var err error @@ -129,7 +129,7 @@ func (srv *Server) getMessage() (interface{}, error) { return nil, fmt.Errorf("从body中解析xml失败,err=%v", err) } - //验证消息签名 + // 验证消息签名 timestamp := srv.Query("timestamp") srv.timestamp, err = strconv.ParseInt(timestamp, 10, 32) if err != nil { @@ -143,7 +143,7 @@ func (srv *Server) getMessage() (interface{}, error) { return nil, fmt.Errorf("消息不合法,验证签名失败") } - //解密 + // 解密 srv.random, rawXMLMsgBytes, err = util.DecryptMsg(srv.AppID, encryptedXMLMsg.EncryptedMsg, srv.EncodingAESKey) if err != nil { return nil, fmt.Errorf("消息解密失败, err=%v", err) @@ -166,7 +166,7 @@ func (srv *Server) parseRequestMessage(rawXMLMsgBytes []byte) (msg *message.MixM return } -//SetMessageHandler 设置用户自定义的回调方法 +// SetMessageHandler 设置用户自定义的回调方法 func (srv *Server) SetMessageHandler(handler func(*message.MixMessage) *message.Reply) { srv.messageHandler = handler } @@ -178,7 +178,7 @@ func (srv *Server) buildResponse(reply *message.Reply) (err error) { } }() if reply == nil { - //do nothing + // do nothing return nil } msgType := reply.MsgType @@ -197,7 +197,7 @@ func (srv *Server) buildResponse(reply *message.Reply) (err error) { msgData := reply.MsgData value := reflect.ValueOf(msgData) - //msgData must be a ptr + // msgData must be a ptr kind := value.Kind().String() if kind != "ptr" { return message.ErrUnsupportReply @@ -221,18 +221,18 @@ func (srv *Server) buildResponse(reply *message.Reply) (err error) { return } -//Send 将自定义的消息发送 +// Send 将自定义的消息发送 func (srv *Server) Send() (err error) { replyMsg := srv.ResponseMsg log.Debugf("response msg =%+v", replyMsg) if srv.isSafeMode { - //安全模式下对消息进行加密 + // 安全模式下对消息进行加密 var encryptedMsg []byte encryptedMsg, err = util.EncryptMsg(srv.random, srv.ResponseRawXMLMsg, srv.AppID, srv.EncodingAESKey) if err != nil { return } - //TODO 如果获取不到timestamp nonce 则自己生成 + // TODO 如果获取不到timestamp nonce 则自己生成 timestamp := srv.timestamp timestampStr := strconv.FormatInt(timestamp, 10) msgSignature := util.Signature(srv.Token, timestampStr, srv.nonce, string(encryptedMsg)) diff --git a/officialaccount/server/util.go b/officialaccount/server/util.go index 6c108fa..5c2ceb2 100644 --- a/officialaccount/server/util.go +++ b/officialaccount/server/util.go @@ -15,10 +15,10 @@ func writeContextType(w http.ResponseWriter, value []string) { } } -//Render render from bytes +// Render render from bytes func (srv *Server) Render(bytes []byte) { - //debug - //fmt.Println("response msg = ", string(bytes)) + // debug + // fmt.Println("response msg = ", string(bytes)) srv.Writer.WriteHeader(200) _, err := srv.Writer.Write(bytes) if err != nil { @@ -26,13 +26,13 @@ func (srv *Server) Render(bytes []byte) { } } -//String render from string +// String render from string func (srv *Server) String(str string) { writeContextType(srv.Writer, plainContentType) srv.Render([]byte(str)) } -//XML render to xml +// XML render to xml func (srv *Server) XML(obj interface{}) { writeContextType(srv.Writer, xmlContentType) bytes, err := xml.Marshal(obj) diff --git a/officialaccount/user/migrate.go b/officialaccount/user/migrate.go index 97e63f0..44afe05 100644 --- a/officialaccount/user/migrate.go +++ b/officialaccount/user/migrate.go @@ -1,5 +1,5 @@ -//Package user migrate 用于微信公众号账号迁移,获取openID变化 -//参考文档:https://kf.qq.com/faq/1901177NrqMr190117nqYJze.html +// Package user migrate 用于微信公众号账号迁移,获取openID变化 +// 参考文档:https://kf.qq.com/faq/1901177NrqMr190117nqYJze.html package user import ( @@ -32,7 +32,7 @@ type ChangeOpenIDResultList struct { // AccessToken 为新账号的AccessToken func (user *User) ListChangeOpenIDs(fromAppID string, openIDs ...string) (list *ChangeOpenIDResultList, err error) { list = &ChangeOpenIDResultList{} - //list.List = make([]ChangeOpenIDResult, 0) + // list.List = make([]ChangeOpenIDResult, 0) if len(openIDs) > 100 { err = errors.New("openIDs length must be lt 100") return diff --git a/officialaccount/user/tag.go b/officialaccount/user/tag.go index d2f07a1..3a61c5d 100644 --- a/officialaccount/user/tag.go +++ b/officialaccount/user/tag.go @@ -18,7 +18,7 @@ const ( tagUserTidListURL = "https://api.weixin.qq.com/cgi-bin/tags/getidlist?access_token=%s" ) -//TagInfo 标签信息 +// TagInfo 标签信息 type TagInfo struct { ID int32 `json:"id"` Name string `json:"name"` @@ -34,7 +34,7 @@ type TagOpenIDList struct { NextOpenID string `json:"next_openid"` } -//CreateTag 创建标签 +// CreateTag 创建标签 func (user *User) CreateTag(tagName string) (tagInfo *TagInfo, err error) { var accessToken string accessToken, err = user.GetAccessToken() @@ -68,7 +68,7 @@ func (user *User) CreateTag(tagName string) (tagInfo *TagInfo, err error) { return result.Tag, nil } -//DeleteTag 删除标签 +// DeleteTag 删除标签 func (user *User) DeleteTag(tagID int32) (err error) { accessToken, err := user.GetAccessToken() if err != nil { @@ -88,7 +88,7 @@ func (user *User) DeleteTag(tagID int32) (err error) { return util.DecodeWithCommonError(resp, "DeleteTag") } -//UpdateTag 编辑标签 +// UpdateTag 编辑标签 func (user *User) UpdateTag(tagID int32, tagName string) (err error) { accessToken, err := user.GetAccessToken() if err != nil { @@ -110,7 +110,7 @@ func (user *User) UpdateTag(tagID int32, tagName string) (err error) { return util.DecodeWithCommonError(resp, "UpdateTag") } -//GetTag 获取公众号已创建的标签 +// GetTag 获取公众号已创建的标签 func (user *User) GetTag() (tags []*TagInfo, err error) { accessToken, err := user.GetAccessToken() if err != nil { @@ -132,7 +132,7 @@ func (user *User) GetTag() (tags []*TagInfo, err error) { return result.Tags, nil } -//OpenIDListByTag 获取标签下粉丝列表 +// OpenIDListByTag 获取标签下粉丝列表 func (user *User) OpenIDListByTag(tagID int32, nextOpenID ...string) (userList *TagOpenIDList, err error) { accessToken, err := user.GetAccessToken() if err != nil { @@ -160,7 +160,7 @@ func (user *User) OpenIDListByTag(tagID int32, nextOpenID ...string) (userList * return } -//BatchTag 批量为用户打标签 +// BatchTag 批量为用户打标签 func (user *User) BatchTag(openIDList []string, tagID int32) (err error) { accessToken, err := user.GetAccessToken() if err != nil { @@ -184,7 +184,7 @@ func (user *User) BatchTag(openIDList []string, tagID int32) (err error) { return util.DecodeWithCommonError(resp, "BatchTag") } -//BatchUntag 批量为用户取消标签 +// BatchUntag 批量为用户取消标签 func (user *User) BatchUntag(openIDList []string, tagID int32) (err error) { if len(openIDList) == 0 { return @@ -208,7 +208,7 @@ func (user *User) BatchUntag(openIDList []string, tagID int32) (err error) { return util.DecodeWithCommonError(resp, "BatchUntag") } -//UserTidList 获取用户身上的标签列表 +// UserTidList 获取用户身上的标签列表 func (user *User) UserTidList(openID string) (tagIDList []int32, err error) { accessToken, err := user.GetAccessToken() if err != nil { diff --git a/officialaccount/user/user.go b/officialaccount/user/user.go index 8cffa36..ebbafc9 100644 --- a/officialaccount/user/user.go +++ b/officialaccount/user/user.go @@ -15,19 +15,19 @@ const ( userListURL = "https://api.weixin.qq.com/cgi-bin/user/get" ) -//User 用户管理 +// User 用户管理 type User struct { *context.Context } -//NewUser 实例化 +// NewUser 实例化 func NewUser(context *context.Context) *User { user := new(User) user.Context = context return user } -//Info 用户基本信息 +// Info 用户基本信息 type Info struct { util.CommonError @@ -62,7 +62,7 @@ type OpenidList struct { NextOpenID string `json:"next_openid"` } -//GetUserInfo 获取用户基本信息 +// GetUserInfo 获取用户基本信息 func (user *User) GetUserInfo(openID string) (userInfo *Info, err error) { var accessToken string accessToken, err = user.GetAccessToken() diff --git a/openplatform/account/account.go b/openplatform/account/account.go index c91ed9e..29b231c 100644 --- a/openplatform/account/account.go +++ b/openplatform/account/account.go @@ -2,33 +2,33 @@ package account import "github.com/silenceper/wechat/v2/openplatform/context" -//Account 开放平台张哈管理 -//TODO 实现方法 +// Account 开放平台张哈管理 +// TODO 实现方法 type Account struct { *context.Context } -//NewAccount new +// NewAccount new func NewAccount(ctx *context.Context) *Account { return &Account{ctx} } -//Create 创建开放平台帐号并绑定公众号/小程序 +// Create 创建开放平台帐号并绑定公众号/小程序 func (account *Account) Create(appID string) (string, error) { return "", nil } -//Bind 将公众号/小程序绑定到开放平台帐号下 +// Bind 将公众号/小程序绑定到开放平台帐号下 func (account *Account) Bind(appID string) error { return nil } -//Unbind 将公众号/小程序从开放平台帐号下解绑 +// Unbind 将公众号/小程序从开放平台帐号下解绑 func (account *Account) Unbind(appID string, openAppID string) error { return nil } -//Get 获取公众号/小程序所绑定的开放平台帐号 +// Get 获取公众号/小程序所绑定的开放平台帐号 func (account *Account) Get(appID string) (string, error) { return "", nil } diff --git a/openplatform/config/config.go b/openplatform/config/config.go index 1c20d38..98e7c4e 100644 --- a/openplatform/config/config.go +++ b/openplatform/config/config.go @@ -4,11 +4,11 @@ import ( "github.com/silenceper/wechat/v2/cache" ) -//Config config for 微信开放平台 +// Config .config for 微信开放平台 type Config struct { - AppID string `json:"app_id"` //appid - AppSecret string `json:"app_secret"` //appsecret - Token string `json:"token"` //token - EncodingAESKey string `json:"encoding_aes_key"` //EncodingAESKey + AppID string `json:"app_id"` // appid + AppSecret string `json:"app_secret"` // appsecret + Token string `json:"token"` // token + EncodingAESKey string `json:"encoding_aes_key"` // EncodingAESKey Cache cache.Cache } diff --git a/openplatform/context/accessToken.go b/openplatform/context/accessToken.go index ed41e42..7e42ed7 100644 --- a/openplatform/context/accessToken.go +++ b/openplatform/context/accessToken.go @@ -1,4 +1,4 @@ -//Package context 开放平台相关context +// Package context 开放平台相关context package context import ( @@ -18,10 +18,10 @@ const ( getComponentInfoURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=%s" componentLoginURL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=%d&biz_appid=%s" bindComponentURL = "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=%d&no_scan=1&component_appid=%s&pre_auth_code=%s&redirect_uri=%s&biz_appid=%s#wechat_redirect" - //TODO 获取授权方选项信息 - //getComponentConfigURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option?component_access_token=%s" - //TODO 获取已授权的账号信息 - //getuthorizerListURL = "POST https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=%s" + // TODO 获取授权方选项信息 + // getComponentConfigURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option?component_access_token=%s" + // TODO 获取已授权的账号信息 + // getuthorizerListURL = "POST https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=%s" ) // ComponentAccessToken 第三方平台 diff --git a/openplatform/miniprogram/basic/basic.go b/openplatform/miniprogram/basic/basic.go index 41389f0..a6e4ad3 100644 --- a/openplatform/miniprogram/basic/basic.go +++ b/openplatform/miniprogram/basic/basic.go @@ -11,23 +11,23 @@ const ( getAccountBasicInfoURL = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo" ) -//Basic 基础信息设置 +// Basic 基础信息设置 type Basic struct { *openContext.Context appID string } -//NewBasic new +// NewBasic new func NewBasic(opContext *openContext.Context, appID string) *Basic { return &Basic{Context: opContext, appID: appID} } -//AccountBasicInfo 基础信息 +// AccountBasicInfo 基础信息 type AccountBasicInfo struct { util.CommonError } -//GetAccountBasicInfo 获取小程序基础信息 +// GetAccountBasicInfo 获取小程序基础信息 //reference:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Mini_Program_Information_Settings.html func (basic *Basic) GetAccountBasicInfo() (*AccountBasicInfo, error) { ak, err := basic.GetAuthrAccessToken(basic.AppID) @@ -46,7 +46,7 @@ func (basic *Basic) GetAccountBasicInfo() (*AccountBasicInfo, error) { return result, nil } -//modify_domain设置服务器域名 -//TODO -//func (encryptor *Basic) modifyDomain() { -//} +// modify_domain设置服务器域名 +// TODO +// func (encryptor *Basic) modifyDomain() { +// } diff --git a/openplatform/miniprogram/component/component.go b/openplatform/miniprogram/component/component.go index 8a5ff22..2ad70e0 100644 --- a/openplatform/miniprogram/component/component.go +++ b/openplatform/miniprogram/component/component.go @@ -11,28 +11,28 @@ const ( fastregisterweappURL = "https://api.weixin.qq.com/cgi-bin/component/fastregisterweapp" ) -//Component 快速创建小程序 +// Component 快速创建小程序 type Component struct { *openContext.Context } -//NewComponent new +// NewComponent new func NewComponent(opContext *openContext.Context) *Component { return &Component{opContext} } -//RegisterMiniProgramParam 快速注册小程序参数 +// RegisterMiniProgramParam 快速注册小程序参数 type RegisterMiniProgramParam struct { - Name string `json:"name"` //企业名 - Code string `json:"code"` //企业代码 - CodeType string `json:"code_type"` //企业代码类型 1:统一社会信用代码(18 位) 2:组织机构代码(9 位 xxxxxxxx-x) 3:营业执照注册号(15 位) - LegalPersonaWechat string `json:"legal_persona_wechat"` //法人微信号 - LegalPersonaName string `json:"legal_persona_name"` //法人姓名(绑定银行卡) - ComponentPhone string `json:"component_phone"` //第三方联系电话(方便法人与第三方联系) + Name string `json:"name"` // 企业名 + Code string `json:"code"` // 企业代码 + CodeType string `json:"code_type"` // 企业代码类型 1:统一社会信用代码(18 位) 2:组织机构代码(9 位 xxxxxxxx-x) 3:营业执照注册号(15 位) + LegalPersonaWechat string `json:"legal_persona_wechat"` // 法人微信号 + LegalPersonaName string `json:"legal_persona_name"` // 法人姓名(绑定银行卡) + ComponentPhone string `json:"component_phone"` // 第三方联系电话(方便法人与第三方联系) } -//RegisterMiniProgram 快速创建小程 -//reference: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Fast_Registration_Interface_document.html +// RegisterMiniProgram 快速创建小程 +// reference: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Fast_Registration_Interface_document.html func (component *Component) RegisterMiniProgram(param *RegisterMiniProgramParam) error { componentAK, err := component.GetComponentAccessToken() if err != nil { @@ -46,15 +46,15 @@ func (component *Component) RegisterMiniProgram(param *RegisterMiniProgramParam) return util.DecodeWithCommonError(data, "component/fastregisterweapp?action=create") } -//GetRegistrationStatusParam 查询任务创建状态 +// GetRegistrationStatusParam 查询任务创建状态 type GetRegistrationStatusParam struct { - Name string `json:"name"` //企业名 - LegalPersonaWechat string `json:"legal_persona_wechat"` //法人微信号 - LegalPersonaName string `json:"legal_persona_name"` //法人姓名(绑定银行卡) + Name string `json:"name"` // 企业名 + LegalPersonaWechat string `json:"legal_persona_wechat"` // 法人微信号 + LegalPersonaName string `json:"legal_persona_name"` // 法人姓名(绑定银行卡) } -//GetRegistrationStatus 查询创建任务状态. +// GetRegistrationStatus 查询创建任务状态. func (component *Component) GetRegistrationStatus(param *GetRegistrationStatusParam) error { componentAK, err := component.GetComponentAccessToken() if err != nil { diff --git a/openplatform/miniprogram/miniprogram.go b/openplatform/miniprogram/miniprogram.go index 1f02a51..2b2d738 100644 --- a/openplatform/miniprogram/miniprogram.go +++ b/openplatform/miniprogram/miniprogram.go @@ -6,13 +6,13 @@ import ( "github.com/silenceper/wechat/v2/openplatform/miniprogram/component" ) -//MiniProgram 代小程序实现业务 +// MiniProgram 代小程序实现业务 type MiniProgram struct { AppID string openContext *openContext.Context } -//NewMiniProgram 实例化 +// NewMiniProgram 实例化 func NewMiniProgram(opCtx *openContext.Context, appID string) *MiniProgram { return &MiniProgram{ openContext: opCtx, @@ -20,13 +20,13 @@ func NewMiniProgram(opCtx *openContext.Context, appID string) *MiniProgram { } } -//GetComponent get component -//快速注册小程序相关 +// GetComponent get component +// 快速注册小程序相关 func (miniProgram *MiniProgram) GetComponent() *component.Component { return component.NewComponent(miniProgram.openContext) } -//GetBasic 基础信息设置 +// GetBasic 基础信息设置 func (miniProgram *MiniProgram) GetBasic() *basic.Basic { return basic.NewBasic(miniProgram.openContext, miniProgram.AppID) } diff --git a/openplatform/officialaccount/js/js.go b/openplatform/officialaccount/js/js.go index 160d52f..aca85f5 100644 --- a/openplatform/officialaccount/js/js.go +++ b/openplatform/officialaccount/js/js.go @@ -15,7 +15,7 @@ type Js struct { credential.JsTicketHandle } -//NewJs init +// NewJs init func NewJs(context *context.Context, appID string) *Js { js := new(Js) js.Context = context @@ -24,13 +24,13 @@ func NewJs(context *context.Context, appID string) *Js { return js } -//SetJsTicketHandle 自定义js ticket取值方式 +// SetJsTicketHandle 自定义js ticket取值方式 func (js *Js) SetJsTicketHandle(ticketHandle credential.JsTicketHandle) { js.JsTicketHandle = ticketHandle } -//GetConfig 第三方平台 - 获取jssdk需要的配置参数 -//uri 为当前网页地址 +// GetConfig 第三方平台 - 获取jssdk需要的配置参数 +// uri 为当前网页地址 func (js *Js) GetConfig(uri, appid string) (config *officialJs.Config, err error) { config = new(officialJs.Config) var accessToken string diff --git a/openplatform/officialaccount/oauth/oauth.go b/openplatform/officialaccount/oauth/oauth.go index e8cf1fb..f83dcc0 100644 --- a/openplatform/officialaccount/oauth/oauth.go +++ b/openplatform/officialaccount/oauth/oauth.go @@ -28,14 +28,14 @@ func NewOauth(context *context.Context) *Oauth { return auth } -//GetRedirectURL 第三方平台 - 获取跳转的url地址 +// GetRedirectURL 第三方平台 - 获取跳转的url地址 func (oauth *Oauth) GetRedirectURL(redirectURI, scope, state, appID string) (string, error) { - //url encode + // url encode urlStr := url.QueryEscape(redirectURI) return fmt.Sprintf(platformRedirectOauthURL, appID, urlStr, scope, state, oauth.AppID), nil } -//Redirect 第三方平台 - 跳转到网页授权 +// Redirect 第三方平台 - 跳转到网页授权 func (oauth *Oauth) Redirect(writer http.ResponseWriter, req *http.Request, redirectURI, scope, state, appID string) error { location, err := oauth.GetRedirectURL(redirectURI, scope, state, appID) if err != nil { diff --git a/openplatform/officialaccount/officialaccount.go b/openplatform/officialaccount/officialaccount.go index 7729e90..c5fd09b 100644 --- a/openplatform/officialaccount/officialaccount.go +++ b/openplatform/officialaccount/officialaccount.go @@ -9,15 +9,15 @@ import ( "github.com/silenceper/wechat/v2/openplatform/officialaccount/oauth" ) -//OfficialAccount 代公众号实现业务 +// OfficialAccount 代公众号实现业务 type OfficialAccount struct { - //授权的公众号的appID + // 授权的公众号的appID appID string *officialaccount.OfficialAccount } -//NewOfficialAccount 实例化 -//appID :为授权方公众号 APPID,非开放平台第三方平台 APPID +// NewOfficialAccount 实例化 +// appID :为授权方公众号 APPID,非开放平台第三方平台 APPID func NewOfficialAccount(opCtx *opContext.Context, appID string) *OfficialAccount { officialAccount := officialaccount.NewOfficialAccount(&offConfig.Config{ AppID: opCtx.AppID, @@ -25,7 +25,7 @@ func NewOfficialAccount(opCtx *opContext.Context, appID string) *OfficialAccount Token: opCtx.Token, Cache: opCtx.Cache, }) - //设置获取access_token的函数 + // 设置获取access_token的函数 officialAccount.SetAccessTokenHandle(NewDefaultAuthrAccessToken(opCtx, appID)) return &OfficialAccount{appID: appID, OfficialAccount: officialAccount} } @@ -40,13 +40,13 @@ func (officialAccount *OfficialAccount) PlatformJs() *js.Js { return js.NewJs(officialAccount.GetContext(), officialAccount.appID) } -//DefaultAuthrAccessToken 默认获取授权ak的方法 +// DefaultAuthrAccessToken 默认获取授权ak的方法 type DefaultAuthrAccessToken struct { opCtx *opContext.Context appID string } -//NewDefaultAuthrAccessToken New +// NewDefaultAuthrAccessToken New func NewDefaultAuthrAccessToken(opCtx *opContext.Context, appID string) credential.AccessTokenHandle { return &DefaultAuthrAccessToken{ opCtx: opCtx, @@ -54,7 +54,7 @@ func NewDefaultAuthrAccessToken(opCtx *opContext.Context, appID string) credenti } } -//GetAccessToken 获取ak +// GetAccessToken 获取ak func (ak *DefaultAuthrAccessToken) GetAccessToken() (string, error) { return ak.opCtx.GetAuthrAccessToken(ak.appID) } diff --git a/openplatform/openplatform.go b/openplatform/openplatform.go index b0497f7..80fb82e 100644 --- a/openplatform/openplatform.go +++ b/openplatform/openplatform.go @@ -11,12 +11,12 @@ import ( "github.com/silenceper/wechat/v2/openplatform/officialaccount" ) -//OpenPlatform 微信开放平台相关api +// OpenPlatform 微信开放平台相关api type OpenPlatform struct { *context.Context } -//NewOpenPlatform new openplatform +// NewOpenPlatform new openplatform func NewOpenPlatform(cfg *config.Config) *OpenPlatform { if cfg.Cache == nil { panic("cache 未设置") @@ -27,24 +27,24 @@ func NewOpenPlatform(cfg *config.Config) *OpenPlatform { return &OpenPlatform{ctx} } -//GetServer get server +// GetServer get server func (openPlatform *OpenPlatform) GetServer(req *http.Request, writer http.ResponseWriter) *server.Server { off := officialaccount.NewOfficialAccount(openPlatform.Context, "") return off.GetServer(req, writer) } -//GetOfficialAccount 公众号代处理 +// GetOfficialAccount 公众号代处理 func (openPlatform *OpenPlatform) GetOfficialAccount(appID string) *officialaccount.OfficialAccount { return officialaccount.NewOfficialAccount(openPlatform.Context, appID) } -//GetMiniProgram 小程序代理 +// GetMiniProgram 小程序代理 func (openPlatform *OpenPlatform) GetMiniProgram(appID string) *miniprogram.MiniProgram { return miniprogram.NewMiniProgram(openPlatform.Context, appID) } -//GetAccountManager 账号管理 -//TODO +// GetAccountManager 账号管理 +// TODO func (openPlatform *OpenPlatform) GetAccountManager() *account.Account { return account.NewAccount(openPlatform.Context) } diff --git a/pay/config/config.go b/pay/config/config.go index f5a31e4..b3603cc 100644 --- a/pay/config/config.go +++ b/pay/config/config.go @@ -1,6 +1,6 @@ package config -// Config config for pay +// Config .config for pay type Config struct { AppID string `json:"app_id"` MchID string `json:"mch_id"` diff --git a/pay/notify/notify.go b/pay/notify/notify.go index 4630996..81b1520 100644 --- a/pay/notify/notify.go +++ b/pay/notify/notify.go @@ -4,12 +4,12 @@ import ( "github.com/silenceper/wechat/v2/pay/config" ) -//Notify 回调 +// Notify 回调 type Notify struct { *config.Config } -//NewNotify new +// NewNotify new func NewNotify(cfg *config.Config) *Notify { return &Notify{cfg} } diff --git a/pay/order/pay.go b/pay/order/pay.go index 3da2a08..06319dc 100644 --- a/pay/order/pay.go +++ b/pay/order/pay.go @@ -172,9 +172,9 @@ func (o *Order) BridgeConfig(p *Params) (cfg Config, err error) { // BridgeAppConfig get app bridge config func (o *Order) BridgeAppConfig(p *Params) (cfg ConfigForApp, err error) { var ( - timestamp string = strconv.FormatInt(time.Now().Unix(), 10) - noncestr string = util.RandomStr(32) - _package string = "Sign=WXPay" + timestamp = strconv.FormatInt(time.Now().Unix(), 10) + noncestr = util.RandomStr(32) + _package = "Sign=WXPay" ) order, err := o.PrePayOrder(p) if err != nil { diff --git a/pay/pay.go b/pay/pay.go index bb43557..004ca53 100644 --- a/pay/pay.go +++ b/pay/pay.go @@ -8,12 +8,12 @@ import ( "github.com/silenceper/wechat/v2/pay/transfer" ) -//Pay 微信支付相关API +// Pay 微信支付相关API type Pay struct { cfg *config.Config } -//NewPay 实例化微信支付相关API +// NewPay 实例化微信支付相关API func NewPay(cfg *config.Config) *Pay { return &Pay{cfg} } diff --git a/pay/transfer/transfer_wallet.go b/pay/transfer/transfer_wallet.go index b6dcc91..c79c113 100644 --- a/pay/transfer/transfer_wallet.go +++ b/pay/transfer/transfer_wallet.go @@ -24,7 +24,7 @@ func NewTransfer(cfg *config.Config) *Transfer { return &transfer } -//Params 调用参数 +// Params 调用参数 type Params struct { DeviceInfo string PartnerTradeNo string @@ -34,10 +34,10 @@ type Params struct { Amount int Desc string SpbillCreateIP string - RootCa string //ca证书 + RootCa string // ca证书 } -//request 接口请求参数 +// request 接口请求参数 type request struct { AppID string `xml:"mch_appid"` MchID string `xml:"mchid"` @@ -53,7 +53,7 @@ type request struct { SpbillCreateIP string `xml:"spbill_create_ip,omitempty"` } -//Response 接口返回 +// Response 接口返回 type Response struct { ReturnCode string `xml:"return_code"` ReturnMsg string `xml:"return_msg"` @@ -69,7 +69,7 @@ type Response struct { PaymentTime string `xml:"payment_time"` } -//WalletTransfer 付款到零钱 +// WalletTransfer 付款到零钱 func (transfer *Transfer) WalletTransfer(p *Params) (rsp Response, err error) { nonceStr := util.RandomStr(32) param := make(map[string]string) diff --git a/util/crypto.go b/util/crypto.go index 1c98d73..815b705 100644 --- a/util/crypto.go +++ b/util/crypto.go @@ -40,7 +40,7 @@ func EncryptMsg(random, rawXMLMsg []byte, appID, aesKey string) (encrtptMsg []by } // AESEncryptMsg ciphertext = AES_Encrypt[random(16B) + msg_len(4B) + rawXMLMsg + appId] -//参考:github.com/chanxuehong/wechat.v2 +// 参考:github.com/chanxuehong/wechat.v2 func AESEncryptMsg(random, rawXMLMsg []byte, appID string, aesKey []byte) (ciphertext []byte) { const ( BlockSize = 32 // PKCS#7 @@ -123,7 +123,7 @@ func aesKeyDecode(encodedAESKey string) (key []byte, err error) { } // AESDecryptMsg ciphertext = AES_Encrypt[random(16B) + msg_len(4B) + rawXMLMsg + appId] -//参考:github.com/chanxuehong/wechat.v2 +// 参考:github.com/chanxuehong/wechat.v2 func AESDecryptMsg(ciphertext []byte, aesKey []byte) (random, rawXMLMsg, appID []byte, err error) { const ( BlockSize = 32 // PKCS#7 diff --git a/util/http.go b/util/http.go index dd2788e..2445341 100644 --- a/util/http.go +++ b/util/http.go @@ -17,7 +17,7 @@ import ( "golang.org/x/crypto/pkcs12" ) -//HTTPGet get 请求 +// HTTPGet get 请求 func HTTPGet(uri string) ([]byte, error) { response, err := http.Get(uri) if err != nil { @@ -31,7 +31,7 @@ func HTTPGet(uri string) ([]byte, error) { return ioutil.ReadAll(response.Body) } -//HTTPPost post 请求 +// HTTPPost post 请求 func HTTPPost(uri string, data string) ([]byte, error) { body := bytes.NewBuffer([]byte(data)) response, err := http.Post(uri, "", body) @@ -46,7 +46,7 @@ func HTTPPost(uri string, data string) ([]byte, error) { return ioutil.ReadAll(response.Body) } -//PostJSON post json 数据请求 +// PostJSON post json 数据请求 func PostJSON(uri string, obj interface{}) ([]byte, error) { jsonBuf := new(bytes.Buffer) enc := json.NewEncoder(jsonBuf) @@ -91,7 +91,7 @@ func PostJSONWithRespContentType(uri string, obj interface{}) ([]byte, string, e return responseData, contentType, err } -//PostFile 上传文件 +// PostFile 上传文件 func PostFile(fieldname, filename, uri string) ([]byte, error) { fields := []MultipartFormField{ { @@ -103,7 +103,7 @@ func PostFile(fieldname, filename, uri string) ([]byte, error) { return PostMultipartForm(fields, uri) } -//MultipartFormField 保存文件或其他字段信息 +// MultipartFormField 保存文件或其他字段信息 type MultipartFormField struct { IsFile bool Fieldname string @@ -111,7 +111,7 @@ type MultipartFormField struct { Filename string } -//PostMultipartForm 上传文件或其他多个字段 +// PostMultipartForm 上传文件或其他多个字段 func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte, err error) { bodyBuf := &bytes.Buffer{} bodyWriter := multipart.NewWriter(bodyBuf) @@ -163,7 +163,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte return } -//PostXML perform a HTTP/POST request with XML body +// PostXML perform a HTTP/POST request with XML body func PostXML(uri string, obj interface{}) ([]byte, error) { xmlData, err := xml.Marshal(obj) if err != nil { @@ -183,7 +183,7 @@ func PostXML(uri string, obj interface{}) ([]byte, error) { return ioutil.ReadAll(response.Body) } -//httpWithTLS CA证书 +// httpWithTLS CA证书 func httpWithTLS(rootCa, key string) (*http.Client, error) { var client *http.Client certData, err := ioutil.ReadFile(rootCa) @@ -202,7 +202,7 @@ func httpWithTLS(rootCa, key string) (*http.Client, error) { return client, nil } -//pkcs12ToPem 将Pkcs12转成Pem +// pkcs12ToPem 将Pkcs12转成Pem func pkcs12ToPem(p12 []byte, password string) tls.Certificate { blocks, err := pkcs12.ToPEM(p12, password) defer func() { @@ -224,7 +224,7 @@ func pkcs12ToPem(p12 []byte, password string) tls.Certificate { return cert } -//PostXMLWithTLS perform a HTTP/POST request with XML body and TLS +// PostXMLWithTLS perform a HTTP/POST request with XML body and TLS func PostXMLWithTLS(uri string, obj interface{}, ca, key string) ([]byte, error) { xmlData, err := xml.Marshal(obj) if err != nil { diff --git a/util/signature.go b/util/signature.go index 22a9cc5..2deb8e2 100644 --- a/util/signature.go +++ b/util/signature.go @@ -7,7 +7,7 @@ import ( "sort" ) -//Signature sha1签名 +// Signature sha1签名 func Signature(params ...string) string { sort.Strings(params) h := sha1.New() diff --git a/util/signature_test.go b/util/signature_test.go index 9aa2f7f..b1e8216 100644 --- a/util/signature_test.go +++ b/util/signature_test.go @@ -3,7 +3,7 @@ package util import "testing" func TestSignature(t *testing.T) { - //abc sig + // abc sig abc := "a9993e364706816aba3e25717850c26c9cd0d89d" if abc != Signature("a", "b", "c") { t.Error("test Signature Error") diff --git a/util/string.go b/util/string.go index 62b5c13..8179b70 100644 --- a/util/string.go +++ b/util/string.go @@ -5,7 +5,7 @@ import ( "time" ) -//RandomStr 随机生成字符串 +// RandomStr 随机生成字符串 func RandomStr(length int) string { str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" bytes := []byte(str) diff --git a/util/time.go b/util/time.go index 91d31ba..b124b93 100644 --- a/util/time.go +++ b/util/time.go @@ -2,7 +2,7 @@ package util import "time" -//GetCurrTS return current timestamps +// GetCurrTS return current timestamps func GetCurrTS() int64 { return time.Now().Unix() } diff --git a/util/util.go b/util/util.go index f18d6fb..a043e0f 100644 --- a/util/util.go +++ b/util/util.go @@ -1,6 +1,6 @@ package util -//SliceChunk 用于将字符串切片分块 +// SliceChunk 用于将字符串切片分块 func SliceChunk(src []string, chunkSize int) (chunks [][]string) { total := len(src) chunks = make([][]string, 0) diff --git a/wechat.go b/wechat.go index cc1204e..f757122 100644 --- a/wechat.go +++ b/wechat.go @@ -39,12 +39,12 @@ func NewWechat() *Wechat { return &Wechat{} } -//SetCache 设置cache +// SetCache 设置cache func (wc *Wechat) SetCache(cahce cache.Cache) { wc.cache = cahce } -//GetOfficialAccount 获取微信公众号实例 +// GetOfficialAccount 获取微信公众号实例 func (wc *Wechat) GetOfficialAccount(cfg *offConfig.Config) *officialaccount.OfficialAccount { if cfg.Cache == nil { cfg.Cache = wc.cache diff --git a/work/kf/servicestate.go b/work/kf/servicestate.go index ecc1a44..cbf467a 100644 --- a/work/kf/servicestate.go +++ b/work/kf/servicestate.go @@ -8,7 +8,7 @@ import ( ) const ( - //获取会话状态 + // 获取会话状态 serviceStateGetAddr = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/get?access_token=%s" // 变更会话状态 serviceStateTransAddr = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/trans?access_token=%s" @@ -28,11 +28,11 @@ type ServiceStateGetSchema struct { } // ServiceStateGet 获取会话状态 -//0 未处理 新会话接入。可选择:1.直接用API自动回复消息。2.放进待接入池等待接待人员接待。3.指定接待人员进行接待 -//1 由智能助手接待 可使用API回复消息。可选择转入待接入池或者指定接待人员处理。 -//2 待接入池排队中 在待接入池中排队等待接待人员接入。可选择转为指定人员接待 -//3 由人工接待 人工接待中。可选择结束会话 -//4 已结束 会话已经结束或未开始。不允许变更会话状态,等待用户发起咨询 +// 0 未处理 新会话接入。可选择:1.直接用API自动回复消息。2.放进待接入池等待接待人员接待。3.指定接待人员进行接待 +// 1 由智能助手接待 可使用API回复消息。可选择转入待接入池或者指定接待人员处理。 +// 2 待接入池排队中 在待接入池中排队等待接待人员接入。可选择转为指定人员接待 +// 3 由人工接待 人工接待中。可选择结束会话 +// 4 已结束 会话已经结束或未开始。不允许变更会话状态,等待用户发起咨询 // 注:一个微信用户向一个客服帐号发起咨询后,在48h内,或主动结束会话前(包括接待人员手动结束,或企业通过API结束会话),都算是一次会话 func (r *Client) ServiceStateGet(options ServiceStateGetOptions) (info ServiceStateGetSchema, err error) { var ( diff --git a/work/msgaudit/client_linux.go b/work/msgaudit/client_linux.go index 37c8e59..9b1c04d 100644 --- a/work/msgaudit/client_linux.go +++ b/work/msgaudit/client_linux.go @@ -1,6 +1,7 @@ +//go:build linux && cgo && msgaudit // +build linux,cgo,msgaudit -//Package msgaudit only for linux +// Package msgaudit only for linux package msgaudit // #cgo LDFLAGS: -L${SRCDIR}/lib -lWeWorkFinanceSdk_C diff --git a/work/msgaudit/client_unsupport.go b/work/msgaudit/client_unsupport.go index 066a2b0..60f1151 100644 --- a/work/msgaudit/client_unsupport.go +++ b/work/msgaudit/client_unsupport.go @@ -1,6 +1,7 @@ +//go:build !linux || !cgo || !msgaudit // +build !linux !cgo !msgaudit -//Package msgaudit for unsupport platform +// Package msgaudit for unsupport platform package msgaudit import ( diff --git a/work/oauth/oauth.go b/work/oauth/oauth.go index 296dbaf..eb0e175 100644 --- a/work/oauth/oauth.go +++ b/work/oauth/oauth.go @@ -9,30 +9,30 @@ import ( "github.com/silenceper/wechat/v2/work/context" ) -//Oauth auth +// Oauth auth type Oauth struct { *context.Context } var ( - //oauthTargetURL 企业微信内跳转地址 + // oauthTargetURL 企业微信内跳转地址 oauthTargetURL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect" - //oauthUserInfoURL 获取用户信息地址 + // oauthUserInfoURL 获取用户信息地址 oauthUserInfoURL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=%s&code=%s" - //oauthQrContentTargetURL 构造独立窗口登录二维码 + // oauthQrContentTargetURL 构造独立窗口登录二维码 oauthQrContentTargetURL = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=%s&agentid=%s&redirect_uri=%s&state=%s" ) -//NewOauth new init oauth +// NewOauth new init oauth func NewOauth(ctx *context.Context) *Oauth { return &Oauth{ ctx, } } -//GetTargetURL 获取授权地址 +// GetTargetURL 获取授权地址 func (ctr *Oauth) GetTargetURL(callbackURL string) string { - //url encode + // url encode urlStr := url.QueryEscape(callbackURL) return fmt.Sprintf( oauthTargetURL, @@ -41,9 +41,9 @@ func (ctr *Oauth) GetTargetURL(callbackURL string) string { ) } -//GetQrContentTargetURL 构造独立窗口登录二维码 +// GetQrContentTargetURL 构造独立窗口登录二维码 func (ctr *Oauth) GetQrContentTargetURL(callbackURL string) string { - //url encode + // url encode urlStr := url.QueryEscape(callbackURL) return fmt.Sprintf( oauthQrContentTargetURL, @@ -54,17 +54,17 @@ func (ctr *Oauth) GetQrContentTargetURL(callbackURL string) string { ) } -//ResUserInfo 返回得用户信息 +// ResUserInfo 返回得用户信息 type ResUserInfo struct { util.CommonError - //当用户为企业成员时返回 + // 当用户为企业成员时返回 UserID string `json:"UserId"` DeviceID string `json:"DeviceId"` - //非企业成员授权时返回 + // 非企业成员授权时返回 OpenID string `json:"OpenId"` } -//UserFromCode 根据code获取用户信息 +// UserFromCode 根据code获取用户信息 func (ctr *Oauth) UserFromCode(code string) (result ResUserInfo, err error) { var accessToken string accessToken, err = ctr.GetAccessToken() diff --git a/work/work.go b/work/work.go index b974c35..c2b686c 100644 --- a/work/work.go +++ b/work/work.go @@ -14,7 +14,7 @@ type Work struct { ctx *context.Context } -//NewWork init work +// NewWork init work func NewWork(cfg *config.Config) *Work { defaultAkHandle := credential.NewWorkAccessToken(cfg.CorpID, cfg.CorpSecret, credential.CacheKeyWorkPrefix, cfg.Cache) ctx := &context.Context{ @@ -24,12 +24,12 @@ func NewWork(cfg *config.Config) *Work { return &Work{ctx: ctx} } -//GetContext get Context +// GetContext get Context func (wk *Work) GetContext() *context.Context { return wk.ctx } -//GetOauth get oauth +// GetOauth get oauth func (wk *Work) GetOauth() *oauth.Oauth { return oauth.NewOauth(wk.ctx) } From d3d91b8d297fd7c9a593757ea223549aadd0a57b Mon Sep 17 00:00:00 2001 From: JerryTam Date: Thu, 9 Sep 2021 12:22:02 +0800 Subject: [PATCH 05/84] =?UTF-8?q?=E5=AE=9E=E4=BE=8B=E5=8C=96Redis=E6=96=B0?= =?UTF-8?q?=E5=A2=9EdialOpts=E5=8F=82=E6=95=B0=E4=BB=A5=E6=94=AF=E6=8C=81r?= =?UTF-8?q?edis=E6=9B=B4=E5=A4=9A=E6=8B=A8=E5=8F=B7=E8=AE=BE=E7=BD=AE=20(#?= =?UTF-8?q?475)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 实例化Redis新dialOpts参数以支持redis更多拨号设置 * debug * gofmt file * remove go.mod empty line Co-authored-by: Jerry --- cache/redis.go | 7 ++++--- go.mod | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cache/redis.go b/cache/redis.go index f685e6a..6fdf643 100644 --- a/cache/redis.go +++ b/cache/redis.go @@ -23,16 +23,17 @@ type RedisOpts struct { } // NewRedis 实例化 -func NewRedis(opts *RedisOpts) *Redis { +func NewRedis(opts *RedisOpts, dialOpts ...redis.DialOption) *Redis { pool := &redis.Pool{ MaxActive: opts.MaxActive, MaxIdle: opts.MaxIdle, IdleTimeout: time.Second * time.Duration(opts.IdleTimeout), Dial: func() (redis.Conn, error) { - return redis.Dial("tcp", opts.Host, + dialOpts = append(dialOpts, []redis.DialOption{ redis.DialDatabase(opts.Database), redis.DialPassword(opts.Password), - ) + }...) + return redis.Dial("tcp", opts.Host, dialOpts...) }, TestOnBorrow: func(conn redis.Conn, t time.Time) error { if time.Since(t) < time.Minute { diff --git a/go.mod b/go.mod index cce929f..c091722 100644 --- a/go.mod +++ b/go.mod @@ -15,4 +15,4 @@ require ( golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/h2non/gock.v1 v1.0.15 -) +) \ No newline at end of file From bc9f483c8ee551b7aea18c9f1b7a863a782f7986 Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Fri, 10 Sep 2021 10:08:49 +0800 Subject: [PATCH 06/84] =?UTF-8?q?feat:=20=E8=8F=9C=E5=8D=95=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=94=AF=E6=8C=81=E5=8F=91=E9=80=81=E7=BB=93=E6=9D=9F?= =?UTF-8?q?=E6=96=87=E6=9C=AC=20(#477)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:菜单消息支持发送结束文本 Co-authored-by: Afeyer --- work/kf/sendmsg/message.go | 1 + 1 file changed, 1 insertion(+) diff --git a/work/kf/sendmsg/message.go b/work/kf/sendmsg/message.go index 48cc77a..821e63a 100644 --- a/work/kf/sendmsg/message.go +++ b/work/kf/sendmsg/message.go @@ -83,6 +83,7 @@ type Menu struct { MsgMenu struct { HeadContent string `json:"head_content"` // 消息内容,不多于1024字节 List []interface{} `json:"list"` // 菜单项配置 + TailContent string `json:"tail_content"` // 结束文本, 不多于1024字 } `json:"msgmenu"` } From d776f5c40007afb8a5d3118b4787e3575625c12c Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Mon, 13 Sep 2021 10:07:18 +0800 Subject: [PATCH 07/84] =?UTF-8?q?feat:=E5=BE=AE=E4=BF=A1=E5=AE=A2=E6=9C=8D?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=90=91=E5=AE=A2=E6=88=B7=E5=8F=91=E9=80=81?= =?UTF-8?q?=E6=AC=A2=E8=BF=8E=E8=AF=AD=20(#478)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:微信客服支持向客户发送欢迎语 * chore: go fmt file * feat:移除空白文件 --- work/kf/sendmsgonevent.go | 45 +++++++++++++++++++++++++ work/kf/sendmsgonevent/message.go | 55 +++++++++++++++++++++++++++++++ work/kf/syncmsg/message.go | 1 + 3 files changed, 101 insertions(+) create mode 100644 work/kf/sendmsgonevent.go create mode 100644 work/kf/sendmsgonevent/message.go diff --git a/work/kf/sendmsgonevent.go b/work/kf/sendmsgonevent.go new file mode 100644 index 0000000..8060d3a --- /dev/null +++ b/work/kf/sendmsgonevent.go @@ -0,0 +1,45 @@ +package kf + +import ( + "encoding/json" + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + // 发送事件响应消息 + sendMsgOnEventAddr = "https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg_on_event?access_token=%s" +) + +// SendMsgOnEventSchema 发送事件响应消息 +type SendMsgOnEventSchema struct { + util.CommonError + MsgID string `json:"msgid"` // 消息ID。如果请求参数指定了msgid,则原样返回,否则系统自动生成并返回。不多于32字节, 字符串取值范围(正则表达式):[0-9a-zA-Z_-]* +} + +// SendMsgOnEvent 发送事件响应消息 +//「进入会话事件」响应消息: +// 如果满足通过API下发欢迎语条件(条件为:1. 企业没有在管理端配置了原生欢迎语;2. 用户在过去48小时里未收过欢迎语,且未向该用户发过消息),则用户进入会话事件会额外返回一个welcome_code,开发者以此为凭据调用接口(填到该接口code参数),即可向客户发送客服欢迎语。 +// 为了保证用户体验以及避免滥用,开发者仅可在收到相关事件后20秒内调用,且只可调用一次。 +func (r *Client) SendMsgOnEvent(options interface{}) (info SendMsgOnEventSchema, err error) { + var ( + accessToken string + data []byte + ) + accessToken, err = r.ctx.GetAccessToken() + if err != nil { + return + } + data, err = util.PostJSON(fmt.Sprintf(sendMsgOnEventAddr, accessToken), options) + if err != nil { + return + } + if err = json.Unmarshal(data, &info); err != nil { + return + } + if info.ErrCode != 0 { + return info, NewSDKErr(info.ErrCode, info.ErrMsg) + } + return info, nil +} diff --git a/work/kf/sendmsgonevent/message.go b/work/kf/sendmsgonevent/message.go new file mode 100644 index 0000000..16aabfa --- /dev/null +++ b/work/kf/sendmsgonevent/message.go @@ -0,0 +1,55 @@ +package sendmsgonevent + +// Message 发送事件响应消息 +type Message struct { + Code string `json:"code"` // 事件响应消息对应的code。通过事件回调下发,仅可使用一次。 + MsgID string `json:"msgid"` // 消息ID。如果请求参数指定了msgid,则原样返回,否则系统自动生成并返回。不多于32字节,不多于32字节 +} + +// Text 文本消息 +type Text struct { + Message + MsgType string `json:"msgtype"` // 消息类型,此时固定为:text + Text struct { + Content string `json:"content"` // 消息内容,最长不超过2048个字节 + } `json:"text"` // 文本消息 +} + +// Menu 发送菜单消息 +type Menu struct { + Message + MsgType string `json:"msgtype"` // 消息类型,此时固定为:msgmenu + MsgMenu struct { + HeadContent string `json:"head_content"` // 消息内容,不多于1024字节 + List []interface{} `json:"list"` // 菜单项配置 + TailContent string `json:"tail_content"` // 结束文本, 不多于1024字 + } `json:"msgmenu"` +} + +// MenuClick 回复菜单 +type MenuClick struct { + Type string `json:"type"` // 菜单类型: click 回复菜单 + Click struct { + ID string `json:"id"` // 菜单ID, 不少于1字节, 不多于64字节 + Content string `json:"content"` // 菜单显示内容, 不少于1字节, 不多于128字节 + } `json:"click"` +} + +// MenuView 超链接菜单 +type MenuView struct { + Type string `json:"type"` // 菜单类型: view 超链接菜单 + View struct { + URL string `json:"url"` // 点击后跳转的链接, 不少于1字节, 不多于2048字节 + Content string `json:"content"` // 菜单显示内容, 不少于1字节, 不多于1024字节 + } `json:"view"` +} + +// MenuMiniProgram 小程序菜单 +type MenuMiniProgram struct { + Type string `json:"type"` // 菜单类型: miniprogram 小程序菜单 + MiniProgram struct { + AppID string `json:"appid"` // 小程序appid, 不少于1字节, 不多于32字节 + PagePath string `json:"pagepath"` // 点击后进入的小程序页面, 不少于1字节, 不多于1024字节 + Content string `json:"content"` // 菜单显示内容, 不少于1字节, 不多于1024字节 + } `json:"miniprogram"` +} diff --git a/work/kf/syncmsg/message.go b/work/kf/syncmsg/message.go index 7e2d638..d889903 100644 --- a/work/kf/syncmsg/message.go +++ b/work/kf/syncmsg/message.go @@ -120,6 +120,7 @@ type EnterSessionEvent struct { ExternalUserID string `json:"external_userid"` // 客户UserID Scene string `json:"scene"` // 进入会话的场景值,获取客服帐号链接开发者自定义的场景值 SceneParam string `json:"scene_param"` // 进入会话的自定义参数,获取客服帐号链接返回的url,开发者按规范拼接的scene_param参数 + WelcomeCode string `json:"welcome_code"` // 如果满足发送欢迎语条件(条件为:1. 企业没有在管理端配置了原生欢迎语;2. 用户在过去48小时里未收过欢迎语,且未向该用户发过消息),会返回该字段。可用该welcome_code调用发送事件响应消息接口给客户发送欢迎语。 } `json:"event"` // 事件消息 } From 9294950ab51b0af965f889d4f86714c5bcb7fe93 Mon Sep 17 00:00:00 2001 From: youkjw <445142575@qq.com> Date: Mon, 13 Sep 2021 18:58:56 +0800 Subject: [PATCH 08/84] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8D=E4=BC=A0sign?= =?UTF-8?q?=5Ftype=E5=AF=BC=E8=87=B4request=20sign=5Ftype=E6=97=A0?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC=E7=9A=84bug=20(#480)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 接入关闭订单 * test * 删除testing,过不了ci * 避免err覆盖 * 修复不传sign_type导致request sign_type无默认值的bug * 修复不传sign_type导致request sign_type无默认值的bug Co-authored-by: liujianwei --- pay/order/pay.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pay/order/pay.go b/pay/order/pay.go index 06319dc..1abd628 100644 --- a/pay/order/pay.go +++ b/pay/order/pay.go @@ -216,6 +216,11 @@ func (o *Order) PrePayOrder(p *Params) (payOrder PreOrder, err error) { p.NotifyURL = o.NotifyURL // 默认使用order.NotifyURL } + // 签名类型 + if p.SignType == "" { + p.SignType = util.SignTypeMD5 + } + param := map[string]string{ "appid": o.AppID, "body": p.Body, @@ -232,10 +237,6 @@ func (o *Order) PrePayOrder(p *Params) (payOrder PreOrder, err error) { "goods_tag": p.GoodsTag, "notify_url": p.NotifyURL, } - // 签名类型 - if param["sign_type"] == "" { - param["sign_type"] = util.SignTypeMD5 - } if p.TimeExpire != "" { // 如果有传入交易结束时间 From c021336a3c4110fa8ee8027863aef53a75a6855b Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Mon, 13 Sep 2021 19:20:16 +0800 Subject: [PATCH 09/84] =?UTF-8?q?doc:=E5=AE=8C=E5=96=84=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=86=85=E7=9A=84=E6=B3=A8=E9=87=8A=E6=96=87?= =?UTF-8?q?=E6=A1=A3=20(#479)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:微信客服支持向客户发送欢迎语 * chore: go fmt file * feat:移除空白文件 * doc:完善菜单消息内的注释文档 --- work/kf/sendmsg/message.go | 2 +- work/kf/sendmsgonevent/message.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/work/kf/sendmsg/message.go b/work/kf/sendmsg/message.go index 821e63a..f078683 100644 --- a/work/kf/sendmsg/message.go +++ b/work/kf/sendmsg/message.go @@ -82,7 +82,7 @@ type Menu struct { MsgType string `json:"msgtype"` // 消息类型,此时固定为:msgmenu MsgMenu struct { HeadContent string `json:"head_content"` // 消息内容,不多于1024字节 - List []interface{} `json:"list"` // 菜单项配置 + List []interface{} `json:"list"` // 菜单项配置,不能多余10个 TailContent string `json:"tail_content"` // 结束文本, 不多于1024字 } `json:"msgmenu"` } diff --git a/work/kf/sendmsgonevent/message.go b/work/kf/sendmsgonevent/message.go index 16aabfa..f822e3c 100644 --- a/work/kf/sendmsgonevent/message.go +++ b/work/kf/sendmsgonevent/message.go @@ -21,7 +21,7 @@ type Menu struct { MsgType string `json:"msgtype"` // 消息类型,此时固定为:msgmenu MsgMenu struct { HeadContent string `json:"head_content"` // 消息内容,不多于1024字节 - List []interface{} `json:"list"` // 菜单项配置 + List []interface{} `json:"list"` // 菜单项配置,不能多余10个 TailContent string `json:"tail_content"` // 结束文本, 不多于1024字 } `json:"msgmenu"` } From 00b13cda0d529fbfbc4d172f0e4dcb9cec763000 Mon Sep 17 00:00:00 2001 From: okhowang <3352585+okhowang@users.noreply.github.com> Date: Thu, 16 Sep 2021 12:21:40 +0800 Subject: [PATCH 10/84] =?UTF-8?q?=E5=A2=9E=E5=8A=A0iv=E6=A0=A1=E9=AA=8C=20?= =?UTF-8?q?(#482)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/encryptor/encryptor.go | 4 ++++ miniprogram/encryptor/encryptor_test.go | 15 +++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 miniprogram/encryptor/encryptor_test.go diff --git a/miniprogram/encryptor/encryptor.go b/miniprogram/encryptor/encryptor.go index 26a57a5..af3c4c2 100644 --- a/miniprogram/encryptor/encryptor.go +++ b/miniprogram/encryptor/encryptor.go @@ -6,6 +6,7 @@ import ( "encoding/base64" "encoding/json" "errors" + "fmt" "github.com/silenceper/wechat/v2/miniprogram/context" ) @@ -90,6 +91,9 @@ func GetCipherText(sessionKey, encryptedData, iv string) ([]byte, error) { if err != nil { return nil, err } + if len(ivBytes) != aes.BlockSize { + return nil, fmt.Errorf("bad iv length %d", len(ivBytes)) + } block, err := aes.NewCipher(aesKey) if err != nil { return nil, err diff --git a/miniprogram/encryptor/encryptor_test.go b/miniprogram/encryptor/encryptor_test.go new file mode 100644 index 0000000..38b518d --- /dev/null +++ b/miniprogram/encryptor/encryptor_test.go @@ -0,0 +1,15 @@ +package encryptor + +import ( + "encoding/base64" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetCipherText_BadIV(t *testing.T) { + keyData := base64.StdEncoding.EncodeToString([]byte("1234567890123456")) + badData := base64.StdEncoding.EncodeToString([]byte("1")) + _, err := GetCipherText(keyData, badData, badData) + assert.Error(t, err) +} From 1e2f909f3493d263444400262169906fc7838211 Mon Sep 17 00:00:00 2001 From: okhowang <3352585+okhowang@users.noreply.github.com> Date: Fri, 17 Sep 2021 10:11:22 +0800 Subject: [PATCH 11/84] =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8Fauth=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0Context=E6=8E=A5=E5=8F=A3=20(#483)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/auth/auth.go | 15 +++++++++++++-- util/http.go | 23 +++++++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/miniprogram/auth/auth.go b/miniprogram/auth/auth.go index 4f239f7..084bd92 100644 --- a/miniprogram/auth/auth.go +++ b/miniprogram/auth/auth.go @@ -1,6 +1,7 @@ package auth import ( + context2 "context" "encoding/json" "fmt" @@ -43,8 +44,13 @@ type RspCheckEncryptedData struct { // Code2Session 登录凭证校验。 func (auth *Auth) Code2Session(jsCode string) (result ResCode2Session, err error) { + return auth.Code2SessionContext(context2.Background(), jsCode) +} + +// Code2SessionContext 登录凭证校验。 +func (auth *Auth) Code2SessionContext(ctx context2.Context, jsCode string) (result ResCode2Session, err error) { var response []byte - if response, err = util.HTTPGet(fmt.Sprintf(code2SessionURL, auth.AppID, auth.AppSecret, jsCode)); err != nil { + if response, err = util.HTTPGetContext(ctx, fmt.Sprintf(code2SessionURL, auth.AppID, auth.AppSecret, jsCode)); err != nil { return } if err = json.Unmarshal(response, &result); err != nil { @@ -64,6 +70,11 @@ func (auth *Auth) GetPaidUnionID() { // CheckEncryptedData .检查加密信息是否由微信生成(当前只支持手机号加密数据),只能检测最近3天生成的加密数据 func (auth *Auth) CheckEncryptedData(encryptedMsgHash string) (result RspCheckEncryptedData, err error) { + return auth.CheckEncryptedDataContext(context2.Background(), encryptedMsgHash) +} + +// CheckEncryptedDataContext .检查加密信息是否由微信生成(当前只支持手机号加密数据),只能检测最近3天生成的加密数据 +func (auth *Auth) CheckEncryptedDataContext(ctx context2.Context, encryptedMsgHash string) (result RspCheckEncryptedData, err error) { var response []byte var ( at string @@ -71,7 +82,7 @@ func (auth *Auth) CheckEncryptedData(encryptedMsgHash string) (result RspCheckEn if at, err = auth.GetAccessToken(); err != nil { return } - if response, err = util.HTTPPost(fmt.Sprintf(checkEncryptedDataURL, at), "encrypted_msg_hash="+encryptedMsgHash); err != nil { + if response, err = util.HTTPPostContext(ctx, fmt.Sprintf(checkEncryptedDataURL, at), "encrypted_msg_hash="+encryptedMsgHash); err != nil { return } if err = util.DecodeWithError(response, &result, "CheckEncryptedDataAuth"); err != nil { diff --git a/util/http.go b/util/http.go index 2445341..40aefbc 100644 --- a/util/http.go +++ b/util/http.go @@ -2,6 +2,7 @@ package util import ( "bytes" + "context" "crypto/tls" "encoding/json" "encoding/pem" @@ -19,7 +20,16 @@ import ( // HTTPGet get 请求 func HTTPGet(uri string) ([]byte, error) { - response, err := http.Get(uri) + return HTTPGetContext(context.Background(), uri) +} + +// HTTPGetContext get 请求 +func HTTPGetContext(ctx context.Context, uri string) ([]byte, error) { + request, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return nil, err + } + response, err := http.DefaultClient.Do(request) if err != nil { return nil, err } @@ -33,8 +43,17 @@ func HTTPGet(uri string) ([]byte, error) { // HTTPPost post 请求 func HTTPPost(uri string, data string) ([]byte, error) { + return HTTPPostContext(context.Background(), uri, data) +} + +// HTTPPostContext post 请求 +func HTTPPostContext(ctx context.Context, uri string, data string) ([]byte, error) { body := bytes.NewBuffer([]byte(data)) - response, err := http.Post(uri, "", body) + request, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, body) + if err != nil { + return nil, err + } + response, err := http.DefaultClient.Do(request) if err != nil { return nil, err } From 8621e06a01539901c0c2dc3aea206ea7328a11a9 Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Sun, 26 Sep 2021 10:38:52 +0800 Subject: [PATCH 12/84] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=AE=A2=E6=9C=8D=E5=B8=B8=E7=94=A8=E7=9A=84=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=B1=BB=E5=9E=8B=20(#486)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:微信客服支持向客户发送欢迎语 * chore: go fmt file * feat:移除空白文件 * doc:完善菜单消息内的注释文档 * feat: 完善微信客服常用的错误类型 * refactor: 优化SDK错误生成函数 --- work/kf/error.go | 82 +++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/work/kf/error.go b/work/kf/error.go index 5856def..d4e4474 100644 --- a/work/kf/error.go +++ b/work/kf/error.go @@ -17,6 +17,8 @@ const ( SDKUnknownError Error = "未知错误" // SDKInvalidCredential 错误码:40001 SDKInvalidCredential Error = "不合法的secret参数" + // SDKInvalidImageSize 错误码:40009 + SDKInvalidImageSize Error = "无效的图片大小" // SDKInvalidCorpID 错误码:40013 SDKInvalidCorpID Error = "无效的 CorpID" // SDKAccessTokenInvalid 错误码:40014 @@ -25,6 +27,10 @@ const ( SDKValidateSignatureFailed Error = "校验签名错误" // SDKDecryptMSGFailed 错误码:40016 SDKDecryptMSGFailed Error = "消息解密失败" + // SDKMediaIDExceedMinLength 错误码:40058 + SDKMediaIDExceedMinLength Error = "media_id 小于最小长度 1" + // SDKContentContainsSensitiveInformation 错误码:40201 + SDKContentContainsSensitiveInformation Error = "当前客服账号由于涉及敏感信息,已被封禁,请联系企业微信客服处理" // SDKAccessTokenMissing 错误码:41001 SDKAccessTokenMissing Error = "缺少AccessToken参数" // SDKAccessTokenExpired 错误码:42001 @@ -50,46 +56,38 @@ func (r Error) Error() string { return reflect.ValueOf(r).String() } -// NewSDKErr 初始化SDK实例错误信息 -func NewSDKErr(code int64, msgList ...string) Error { - switch code { - case 50001: - return SDKInitFailed - case 50002: - return SDKCacheUnavailable - case 40001: - return SDKInvalidCredential - case 41001: - return SDKAccessTokenMissing - case 42001: - return SDKAccessTokenExpired - case 40013: - return SDKInvalidCorpID - case 40014: - return SDKAccessTokenInvalid - case 40015: - return SDKValidateSignatureFailed - case 40016: - return SDKDecryptMSGFailed - case 45009: - return SDKApiFreqOutOfLimit - case 48002: - return SDKApiForbidden - case 95000: - return SDKInvalidOpenKFID - case 95004: - return SDKOpenKFIDNotExist - case 95011: - return SDKWeWorkAlready - case 95012: - return SDKNotUseInWeCom - case 95017: - return SDKApiNotOpen - default: - //返回未知的自定义错误 - if len(msgList) > 0 { - return Error(strings.Join(msgList, ",")) - } - return SDKUnknownError - } +var codeDic = map[int64]error{ + 50001: SDKInitFailed, + 50002: SDKCacheUnavailable, + 50003: SDKUnknownError, + 40001: SDKInvalidCredential, + 40009: SDKInvalidImageSize, + 40013: SDKInvalidCorpID, + 40014: SDKAccessTokenInvalid, + 40015: SDKValidateSignatureFailed, + 40016: SDKDecryptMSGFailed, + 40058: SDKMediaIDExceedMinLength, + 40201: SDKContentContainsSensitiveInformation, + 41001: SDKAccessTokenMissing, + 42001: SDKAccessTokenExpired, + 45009: SDKApiFreqOutOfLimit, + 48002: SDKApiForbidden, + 95000: SDKInvalidOpenKFID, + 95004: SDKOpenKFIDNotExist, + 95011: SDKWeWorkAlready, + 95012: SDKNotUseInWeCom, + 95017: SDKApiNotOpen, +} + +// NewSDKErr 初始化SDK实例错误信息 +func NewSDKErr(code int64, msgList ...string) error { + if err := codeDic[code]; err != nil { + return err + } + + //返回未知的自定义错误 + if len(msgList) > 0 { + return Error(strings.Join(msgList, ",")) + } + return SDKUnknownError } From fd96154231a4fda42544aa6c6f33132c0edf3c98 Mon Sep 17 00:00:00 2001 From: "owen.gxz" <407953854@qq.com> Date: Sun, 26 Sep 2021 14:15:31 +0800 Subject: [PATCH 13/84] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E4=BA=8B=E4=BB=B6=E6=8E=A8=E9=80=81=E6=B6=88?= =?UTF-8?q?=E6=81=AF=20(#487)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 消息类型增加快速注册企业小程序回调参数 * 代码格式化 * 更改常量名称 * 更改注解 Co-authored-by: 高震 --- officialaccount/message/message.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/officialaccount/message/message.go b/officialaccount/message/message.go index 9a5b659..f6f255f 100644 --- a/officialaccount/message/message.go +++ b/officialaccount/message/message.go @@ -86,6 +86,8 @@ const ( InfoTypeUnauthorized = "unauthorized" // InfoTypeUpdateAuthorized 更新授权 InfoTypeUpdateAuthorized = "updateauthorized" + // InfoTypeNotifyThirdFasterRegister 注册审核事件推送 + InfoTypeNotifyThirdFasterRegister = "notify_third_fasteregister" ) // MixMessage 存放所有微信发送过来的消息和事件 @@ -150,6 +152,15 @@ type MixMessage struct { AuthorizationCode string `xml:"AuthorizationCode"` AuthorizationCodeExpiredTime int64 `xml:"AuthorizationCodeExpiredTime"` PreAuthCode string `xml:"PreAuthCode"` + AuthCode string `xml:"auth_code"` + Info struct { + Name string `xml:"name"` + Code string `xml:"code"` + CodeType int `xml:"code_type"` + LegalPersonaWechat string `xml:"legal_persona_wechat"` + LegalPersonaName string `xml:"legal_persona_name"` + ComponentPhone string `xml:"component_phone"` + } `xml:"info"` // 卡券相关 CardID string `xml:"CardId"` From f74869e61ce866e7c74272a15ecbad7acec0217a Mon Sep 17 00:00:00 2001 From: houseme Date: Mon, 27 Sep 2021 19:35:16 +0800 Subject: [PATCH 14/84] Transfer to wallet returns pointer object (#489) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feature] Format the code and improve Mini Program authorization to obtain openid(miniprogram/auth/auth.go Code2Session) * [feature] CheckEncryptedData (https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/user-info/auth.checkEncryptedData.html) * upgrade json error * upgrade json error * [feature] Wallet Transfer returns the pointer object Co-authored-by: houseme --- pay/transfer/transfer_wallet.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pay/transfer/transfer_wallet.go b/pay/transfer/transfer_wallet.go index c79c113..53a7b09 100644 --- a/pay/transfer/transfer_wallet.go +++ b/pay/transfer/transfer_wallet.go @@ -70,7 +70,7 @@ type Response struct { } // WalletTransfer 付款到零钱 -func (transfer *Transfer) WalletTransfer(p *Params) (rsp Response, err error) { +func (transfer *Transfer) WalletTransfer(p *Params) (rsp *Response, err error) { nonceStr := util.RandomStr(32) param := make(map[string]string) param["mch_appid"] = transfer.AppID @@ -83,11 +83,10 @@ func (transfer *Transfer) WalletTransfer(p *Params) (rsp Response, err error) { if p.DeviceInfo != "" { param["device_info"] = p.DeviceInfo } + param["check_name"] = "NO_CHECK" if p.CheckName { param["check_name"] = "FORCE_CHECK" param["re_user_name"] = p.ReUserName - } else { - param["check_name"] = "NO_CHECK" } if p.SpbillCreateIP != "" { param["spbill_create_ip"] = p.SpbillCreateIP @@ -110,13 +109,11 @@ func (transfer *Transfer) WalletTransfer(p *Params) (rsp Response, err error) { Desc: p.Desc, SpbillCreateIP: p.SpbillCreateIP, } + req.CheckName = "NO_CHECK" if p.CheckName { req.CheckName = "FORCE_CHECK" req.ReUserName = p.ReUserName - } else { - req.CheckName = "NO_CHECK" } - rawRet, err := util.PostXMLWithTLS(walletTransferGateway, req, p.RootCa, transfer.MchID) if err != nil { return From e9489625c69e8ab898cecf69b5e63aacb8ec7e0a Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Thu, 30 Sep 2021 12:13:10 +0800 Subject: [PATCH 15/84] =?UTF-8?q?feat:=E5=BE=AE=E4=BF=A1=E5=AE=A2=E6=9C=8D?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=80=9A=E8=BF=87=E6=8E=A5=E5=8F=A3=E8=BD=AC?= =?UTF-8?q?=E6=8E=A5=E4=BA=BA=E5=B7=A5=E4=BC=9A=E8=AF=9D=20(#492)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/kf/servicestate.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/work/kf/servicestate.go b/work/kf/servicestate.go index cbf467a..4834838 100644 --- a/work/kf/servicestate.go +++ b/work/kf/servicestate.go @@ -28,11 +28,11 @@ type ServiceStateGetSchema struct { } // ServiceStateGet 获取会话状态 -// 0 未处理 新会话接入。可选择:1.直接用API自动回复消息。2.放进待接入池等待接待人员接待。3.指定接待人员进行接待 -// 1 由智能助手接待 可使用API回复消息。可选择转入待接入池或者指定接待人员处理。 -// 2 待接入池排队中 在待接入池中排队等待接待人员接入。可选择转为指定人员接待 -// 3 由人工接待 人工接待中。可选择结束会话 -// 4 已结束 会话已经结束或未开始。不允许变更会话状态,等待用户发起咨询 +// 0 未处理 新会话接入(客户发信咨询)。可选择:1.直接用API自动回复消息。2.放进待接入池等待接待人员接待。3.指定接待人员(接待人员须处于“正在接待”中,下同)进行接待 +// 1 由智能助手接待 可使用API回复消息。可选择转入待接入池或者指定接待人员处理 +// 2 待接入池排队中 在待接入池中排队等待接待人员接入。可选择转为指定人员接待 +// 3 由人工接待 人工接待中。可选择转接给其他接待人员处理或者结束会话 +// 4 已结束 会话已经结束或未开始。不允许变更会话状态,客户重新发信咨询后会话状态变为“未处理” // 注:一个微信用户向一个客服帐号发起咨询后,在48h内,或主动结束会话前(包括接待人员手动结束,或企业通过API结束会话),都算是一次会话 func (r *Client) ServiceStateGet(options ServiceStateGetOptions) (info ServiceStateGetSchema, err error) { var ( From 4937f019a03305819678bb9dee55a541d9965021 Mon Sep 17 00:00:00 2001 From: silenceper Date: Thu, 30 Sep 2021 16:01:47 +0800 Subject: [PATCH 16/84] =?UTF-8?q?=E6=A2=B3=E7=90=86API=E5=88=97=E8=A1=A8?= =?UTF-8?q?=20(#491)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * api梳理 * 完善客服管理api doc --- doc/api/README.md | 18 ++++ doc/api/aispeech.md | 2 + doc/api/minigame.md | 2 + doc/api/miniprogram.md | 2 + doc/api/officialaccount.md | 180 +++++++++++++++++++++++++++++++++++++ doc/api/oplatform.md | 1 + doc/api/work.md | 2 + doc/api/wxpay.md | 2 + 8 files changed, 209 insertions(+) create mode 100644 doc/api/README.md create mode 100644 doc/api/aispeech.md create mode 100644 doc/api/minigame.md create mode 100644 doc/api/miniprogram.md create mode 100644 doc/api/officialaccount.md create mode 100644 doc/api/oplatform.md create mode 100644 doc/api/work.md create mode 100644 doc/api/wxpay.md diff --git a/doc/api/README.md b/doc/api/README.md new file mode 100644 index 0000000..eec6650 --- /dev/null +++ b/doc/api/README.md @@ -0,0 +1,18 @@ +# API 文档 +已完成以及未完成API列表汇总 + +如果有兴趣参与贡献,可以在具体的API表格后面标识自己为贡献者以及完成时间,例如: + + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 |贡献者|完成时间| +| :---------------------: | -------- | :------------------------- | ---------- | -------- |-------- |-------- | +| 获取公众号类目 | GET | /wxaapi/newtmpl/getcategory | NO | |silenceper| 2021-12-20| + + +- [微信公众号](./officialaccount.md) +- [小程序](./miniprogram.md) +- [小游戏](./minigame.md) +- [开放平台](./oplatform.md) +- [微信支付](./wxpay.md) +- [企业微信](./work.md) +- [智能对话](./aispeech.md) diff --git a/doc/api/aispeech.md b/doc/api/aispeech.md new file mode 100644 index 0000000..37d758f --- /dev/null +++ b/doc/api/aispeech.md @@ -0,0 +1,2 @@ +# 智能对话 +TODO diff --git a/doc/api/minigame.md b/doc/api/minigame.md new file mode 100644 index 0000000..db5697d --- /dev/null +++ b/doc/api/minigame.md @@ -0,0 +1,2 @@ +# 小游戏 +TODO \ No newline at end of file diff --git a/doc/api/miniprogram.md b/doc/api/miniprogram.md new file mode 100644 index 0000000..dbc422f --- /dev/null +++ b/doc/api/miniprogram.md @@ -0,0 +1,2 @@ +# 小程序 +TODO \ No newline at end of file diff --git a/doc/api/officialaccount.md b/doc/api/officialaccount.md new file mode 100644 index 0000000..b1d2543 --- /dev/null +++ b/doc/api/officialaccount.md @@ -0,0 +1,180 @@ +# 微信公众号API列表 + +## 基础接口 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| :---------------------: | -------- | :------------------------- | ---------- | -------- | +| 获取Access token | GET | /cgi-bin/token | YES | | +| 获取微信服务器IP地址 | GET | /cgi-bin/get_api_domain_ip | YES | | +| 获取微信callback IP地址 | GET | /cgi-bin/getcallbackip | YES | | +| 清理接口调用次数 | POST | /cgi-bin/clear_quota | YES | | + +## 订阅通知 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Subscription_Messages/api.html) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| -------------------- | -------- | -------------------------------------- | ---------- | ----------------------- | +| 选用模板 | POST | /wxaapi/newtmpl/addtemplate | YES | (tpl *Subscribe) Add | +| 删除模板 | POST | /wxaapi/newtmpl/deltemplate | YES | (tpl *Subscribe) Delete | +| 获取公众号类目 | GET | /wxaapi/newtmpl/getcategory | NO | | +| 获取模板中的关键词 | GET | /wxaapi/newtmpl/getpubtemplatekeywords | NO | | +| 获取类目下的公共模板 | GET | /wxaapi/newtmpl/getpubtemplatetitles | NO | | +| 获取私有模板列表 | GET | /wxaapi/newtmpl/gettemplate | YES | (tpl *Subscribe) List() | +| 发送订阅通知 | POST | /cgi-bin/message/subscribe/bizsend | YES | (tpl *Subscribe) Send | + +## 客服消息 + +### PC 客服能力 + +#### 客服管理 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Customer_Service/Customer_Service_Management.html) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ---------------- | --------- | -------------------------------------- | ---------- | -------- | +| 获取客服基本信息 | GET | /cgi-bin/customservice/getkflist | NO | | +| 添加客服帐号 | POST | /customservice/kfaccount/add | NO | | +| 邀请绑定客服帐号 | POST | /customservice/kfaccount/inviteworker | NO | | +| 设置客服信息 | POST | /customservice/kfaccount/update | NO | | +| 上传客服头像 | POST/FORM | /customservice/kfaccount/uploadheadimg | NO | | +| 删除客服帐号 | GET | /customservice/kfaccount/del | NO | | + +#### 会话控制 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Customer_Service/Session_control.html) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ------------------ | -------- | --------------------------------------- | ---------- | -------- | +| 创建会话 | POST | /customservice/kfsession/create | NO | | +| 获取客户会话状态 | GET | /customservice/kfsession/getsession | NO | | +| 获取客服会话列表 | GET | /customservice/kfsession/getsessionlist | NO | | +| 获取未接入会话列表 | POST | /customservice/kfsession/getwaitcase | NO | | + +#### 获取聊天记录 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Customer_Service/Obtain_chat_transcript.html) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ------------ | -------- | ----------------------------------- | ---------- | -------- | +| 获取聊天记录 | POST | /customservice/msgrecord/getmsglist | NO | | + +### 对话能力 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/guide.html) + +#### 顾问管理 + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ------------------------------ | -------- | -------------------------------------- | ---------- | -------- | +| 添加顾问 | POST | /cgi-bin/guide/addguideacct | NO | | +| 获取顾问信息 | POST | /cgi-bin/guide/getguideacct | NO | | +| 修改顾问信息 | POST | /cgi-bin/guide/updateguideacct | NO | | +| 删除顾问 | POST | /cgi-bin/guide/delguideacct | NO | | +| 获取服务号顾问列表 | POST | /cgi-bin/guide/getguideacctlist | NO | | +| 生成顾问二维码 | POST | /cgi-bin/guide/guidecreateqrcode | NO | | +| 获取顾问聊天记录 | POST | /cgi-bin/guide/getguidebuyerchatrecord | NO | | +| 设置快捷回复与关注自动回复 | POST | /cgi-bin/guide/setguideconfig | NO | | +| 获取快捷回复与关注自动回复 | POST | /cgi-bin/guide/getguideconfig | NO | | +| 设置敏感词与离线自动回复 | POST | /cgi-bin/guide/setguideacctconfig | NO | | +| 获取离线自动回复与敏感词 | POST | /cgi-bin/guide/getguideacctconfig | NO | | +| 允许微信用户复制小程序页面路径 | POST | /cgi-bin/guide/pushshowwxapathmenu | NO | | +| 新建顾问分组 | POST | /cgi-bin/guide/newguidegroup | NO | | +| 获取顾问分组列表 | POST | /cgi-bin/guide/getguidegrouplist | NO | | +| 获取顾问分组信息 | POST | /cgi-bin/guide/getgroupinfo | NO | | +| 分组内添加顾问 | POST | /cgi-bin/guide/addguide2guidegroup | NO | | +| 分组内删除顾问 | POST | /cgi-bin/guide/delguide2guidegroup | NO | | +| 获取顾问所在分组 | POST | /cgi-bin/guide/getgroupbyguide | NO | | +| 删除指定顾问分组 | POST | /cgi-bin/guide/delguidegroup | NO | | + +#### 客户管理 + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ------------------------ | -------- | ------------------------------------------- | ---------- | -------- | +| 为顾问分配客户 | POST | /cgi-bin/guide/addguidebuyerrelation | NO | | +| 为顾问移除客户 | POST | /cgi-bin/guide/delguidebuyerrelation | NO | | +| 获取顾问的客户列表 | POST | /cgi-bin/guide/getguidebuyerrelationlist | NO | | +| 为客户更换顾问 | POST | /cgi-bin/guide/rebindguideacctforbuyer | NO | | +| 修改客户昵称 | POST | /cgi-bin/guide/updateguidebuyerrelation | NO | | +| 查询客户所属顾问 | POST | /cgi-bin/guide/getguidebuyerrelationbybuyer | NO | | +| 查询指定顾问和客户的关系 | POST | /cgi-bin/guide/getguidebuyerrelation | NO | | + +#### 标签管理 + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ------------------ | -------- | -------------------------------------- | ---------- | -------- | +| 新建标签类型 | POST | /cgi-bin/guide/newguidetagoption | NO | | +| 删除标签类型 | POST | /cgi-bin/guide/delguidetagoption | NO | | +| 为标签添加可选值 | POST | /cgi-bin/guide/addguidetagoption | NO | | +| 获取标签和可选值 | POST | /cgi-bin/guide/getguidetagoption | NO | | +| 为客户设置标签 | POST | /cgi-bin/guide/addguidebuyertag | NO | | +| 查询客户标签 | POST | /cgi-bin/guide/getguidebuyertag | NO | | +| 根据标签值筛选客户 | POST | /cgi-bin/guide/queryguidebuyerbytag | NO | | +| 删除客户标签 | POST | /cgi-bin/guide/delguidebuyertag | NO | | +| 设置自定义客户信息 | POST | /cgi-bin/guide/addguidebuyerdisplaytag | NO | | +| 获取自定义客户信息 | POST | /cgi-bin/guide/getguidebuyerdisplaytag | NO | | + +#### 素材管理 + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ------------------ | -------- | ------------------------------------ | ---------- | -------- | +| 添加小程序卡片素材 | POST | /cgi-bin/guide/setguidecardmaterial | NO | | +| 查询小程序卡片素材 | POST | /cgi-bin/guide/getguidecardmaterial | NO | | +| 删除小程序卡片素材 | POST | /cgi-bin/guide/delguidecardmaterial | NO | | +| 添加图片素材 | POST | /cgi-bin/guide/setguideimagematerial | NO | | +| 查询图片素材 | POST | /cgi-bin/guide/getguideimagematerial | NO | | +| 删除图片素材 | POST | /cgi-bin/guide/delguideimagematerial | NO | | +| 添加文字素材 | POST | /cgi-bin/guide/setguidewordmaterial | NO | | +| 查询文字素材 | POST | /cgi-bin/guide/getguidewordmaterial | NO | | +| 删除文字素材 | POST | /cgi-bin/guide/delguidewordmaterial | NO | | + +#### 群发任务管理 + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| -------------------- | -------- | ------------------------------------- | ---------- | -------- | +| 添加群发任务 | POST | /cgi-bin/guide/addguidemassendjob | NO | | +| 获取群发任务列表 | POST | /cgi-bin/guide/getguidemassendjoblist | NO | | +| 获取指定群发任务信息 | POST | /cgi-bin/guide/getguidemassendjob | NO | | +| 修改群发任务 | POST | /cgi-bin/guide/updateguidemassendjob | NO | | +| 取消群发任务 | POST | /cgi-bin/guide/cancelguidemassendjob | NO | | + +## 微信网页开发 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ------------------------------------------------------------ | -------- | --------------------------------------------------- | ---------- | ----------------------------------- | +| 获取跳转的url地址 | GET | https://open.weixin.qq.com/connect/oauth2/authorize | YES | (oauth *Oauth) GetRedirectURL | +| 获取网页应用跳转的url地址 | GET | https://open.weixin.qq.com/connect/qrconnect | YES | (oauth *Oauth) GetWebAppRedirectURL | +| 通过网页授权的code 换取access_token(区别于context中的access_token) | GET | /sns/oauth2/access_token | YES | (oauth *Oauth) GetUserAccessToken | +| 刷新access_token | GET | /sns/oauth2/refresh_token? | YES | (oauth *Oauth) RefreshAccessToken | +| 检验access_token是否有效 | GET | /sns/auth | YES | (oauth *Oauth) CheckAccessToken( | +| 拉取用户信息(需scope为 snsapi_userinfo) | GET | /sns/userinfo | YES | (oauth *Oauth) GetUserInfo | +| 获取jssdk需要的配置参数 | GET | /cgi-bin/ticket/getticket | YES | (js *Js) GetConfig | + +## 素材管理 + +## 图文消息留言管理 + +## 用户管理 + +## 账号管理 + +## 数据统计 + +## 微信卡券 + +## 微信门店 + +## 智能接口 + +## 微信设备功能 + +## 微信“一物一码” + +## 微信发票 + +## 微信非税缴费 + diff --git a/doc/api/oplatform.md b/doc/api/oplatform.md new file mode 100644 index 0000000..69f56ae --- /dev/null +++ b/doc/api/oplatform.md @@ -0,0 +1 @@ +# 开放平台 diff --git a/doc/api/work.md b/doc/api/work.md new file mode 100644 index 0000000..882856e --- /dev/null +++ b/doc/api/work.md @@ -0,0 +1,2 @@ +# 企业微信 +TODO \ No newline at end of file diff --git a/doc/api/wxpay.md b/doc/api/wxpay.md new file mode 100644 index 0000000..6fce640 --- /dev/null +++ b/doc/api/wxpay.md @@ -0,0 +1,2 @@ +# 微信支付 +TODO From 83621a38c6a8b7ee8d7c6cd669a8996625a4b5c9 Mon Sep 17 00:00:00 2001 From: silenceper Date: Thu, 30 Sep 2021 16:09:55 +0800 Subject: [PATCH 17/84] Update README.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a03c9d0..1a64504 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,20 @@ ![Go](https://github.com/silenceper/wechat/workflows/Go/badge.svg?branch=release-2.0) [![Go Report Card](https://goreportcard.com/badge/github.com/silenceper/wechat)](https://goreportcard.com/report/github.com/silenceper/wechat) [![pkg](https://img.shields.io/badge/dev-reference-007d9c?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/silenceper/wechat/v2?tab=doc) +![version](https://img.shields.io/badge/version-v2-green) 使用Golang开发的微信SDK,简单、易用。 ->当前版本为v2版本 +>注意:当前版本为v2版本,v1版本已废弃 ## 文档 && 例子 +[API列表](https://github.com/silenceper/wechat/tree/v2/doc/api) + [Wechat SDK 2.0 文档](https://silenceper.com/wechat) [Wechat SDK 2.0 例子](https://github.com/gowechat/example) + ## 快速开始 ``` import "github.com/silenceper/wechat/v2" @@ -61,8 +65,10 @@ server.Send() - openplatform:开放平台API - work:企业微信 - aispeech:智能对话 +- doc: api文档 ## 贡献 +- 在[API列表](https://github.com/silenceper/wechat/tree/v2/doc/api)中查看哪些API未实现 - 提交issue,描述需要贡献的内容 - 完成更改后,提交PR From a9ae64ef63b26282f4a1063d4f73e3f9c65ce050 Mon Sep 17 00:00:00 2001 From: silenceper Date: Thu, 30 Sep 2021 16:50:29 +0800 Subject: [PATCH 18/84] add work api doc (#494) --- doc/api/work.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/api/work.md b/doc/api/work.md index 882856e..cf39f8a 100644 --- a/doc/api/work.md +++ b/doc/api/work.md @@ -1,2 +1,34 @@ # 企业微信 -TODO \ No newline at end of file + +host: https://qyapi.weixin.qq.com/ + +## 微信客服 + +[官方文档](https://work.weixin.qq.com/api/doc/90000/90135/94638) + +### 客服账号管理 + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| :--------------: | -------- | :-------------------------- | ---------- | ------------------------- | +| 添加客服帐号 | POST | /cgi-bin/kf/account/add | YES | (r *Client) AccountAdd | +| 删除客服帐号 | POST | /cgi-bin/kf/account/del | YES | (r *Client) AccountDel | +| 修改客服帐号 | POST | /cgi-bin/kf/account/update | YES | (r *Client) AccountUpdate | +| 获取客服帐号列表 | GET | /cgi-bin/kf/account/list | YES | (r *Client) AccountList() | +| 获取客服帐号链接 | GET | /cgi-bin/kf/add_contact_way | YES | (r *Client) AddContactWay | + +### 接待人员列表 + +TODO + +### 会话分配与消息收发 + +TODO + +### 其他基础信息获取 + +TODO + +## 应用管理 + +TODO + From ab4f427647aa70215d6b89ad119b23f314e5db9a Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Thu, 30 Sep 2021 17:31:30 +0800 Subject: [PATCH 19/84] =?UTF-8?q?feat:=E5=BE=AE=E4=BF=A1=E5=AE=A2=E6=9C=8D?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=8E=B7=E5=8F=96=E8=A7=86=E9=A2=91=E5=8F=B7?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E7=8A=B6=E6=80=81=20(#493)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/kf/other.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 work/kf/other.go diff --git a/work/kf/other.go b/work/kf/other.go new file mode 100644 index 0000000..94bfcdb --- /dev/null +++ b/work/kf/other.go @@ -0,0 +1,49 @@ +package kf + +import ( + "encoding/json" + "fmt" + + "github.com/silenceper/wechat/v2/util" +) + +const ( + //获取视频号绑定状态 + corpQualification = "https://qyapi.weixin.qq.com/cgi-bin/kf/get_corp_qualification?access_token=%s" +) + +// CorpQualificationSchema 获取视频号绑定状态响应内容 +type CorpQualificationSchema struct { + util.CommonError + WechatChannelsBinding bool `json:"wechat_channels_binding"` // 当企业具有绑定成功的视频号时,返回true,否则返回false。 1. 企业申请绑定视频号且由视频号管理员确认后,才为绑定成功状态 2. 至少有一个绑定成功的视频号就会返回true +} + +// GetCorpQualification 获取视频号绑定状态 +// 微信客服可接待的客户数,和企业是否已完成主体验证、是否绑定视频号相关。 +// +// 企业未完成主体验证时,微信客服仅可累计接待100位客户 +// 企业已验证但未绑定视频号时,微信客服仅可累计接待10000位客户 +// 企业已验证且已绑定视频号时,微信客服可接待的客户数不受限制 +// +// 开发者可获取状态后,在应用等地方提示企业去完成主体验证或绑定视频号。 +func (r *Client) GetCorpQualification() (info CorpQualificationSchema, err error) { + var ( + accessToken string + data []byte + ) + accessToken, err = r.ctx.GetAccessToken() + if err != nil { + return + } + data, err = util.HTTPGet(fmt.Sprintf(corpQualification, accessToken)) + if err != nil { + return info, err + } + if err = json.Unmarshal(data, &info); err != nil { + return + } + if info.ErrCode != 0 { + return info, NewSDKErr(info.ErrCode, info.ErrMsg) + } + return info, nil +} From f5f401e76c8ca9174fcf3a9ea08cd0cf77705e0c Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Thu, 30 Sep 2021 22:34:42 +0800 Subject: [PATCH 20/84] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=AE=A2=E6=9C=8D=20API=20=E6=96=87=E6=A1=A3=20(#495)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * doc: 更新微信客服 API 文档 * chore: 解决【升级服务】标题显示异常的问题 --- doc/api/work.md | 51 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/doc/api/work.md b/doc/api/work.md index cf39f8a..55193cb 100644 --- a/doc/api/work.md +++ b/doc/api/work.md @@ -8,25 +8,56 @@ host: https://qyapi.weixin.qq.com/ ### 客服账号管理 -| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | -| :--------------: | -------- | :-------------------------- | ---------- | ------------------------- | -| 添加客服帐号 | POST | /cgi-bin/kf/account/add | YES | (r *Client) AccountAdd | -| 删除客服帐号 | POST | /cgi-bin/kf/account/del | YES | (r *Client) AccountDel | -| 修改客服帐号 | POST | /cgi-bin/kf/account/update | YES | (r *Client) AccountUpdate | -| 获取客服帐号列表 | GET | /cgi-bin/kf/account/list | YES | (r *Client) AccountList() | -| 获取客服帐号链接 | GET | /cgi-bin/kf/add_contact_way | YES | (r *Client) AddContactWay | +[官方文档](https://open.work.weixin.qq.com/api/doc/90001/90143/94684) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 |贡献者 | +| :--------------: | -------- | :-------------------------- | ---------- | -------------------------------|------------| +| 添加客服帐号 | POST | /cgi-bin/kf/account/add | YES | (r *Client) AccountAdd | NICEXAI | +| 删除客服帐号 | POST | /cgi-bin/kf/account/del | YES | (r *Client) AccountDel | NICEXAI | +| 修改客服帐号 | POST | /cgi-bin/kf/account/update | YES | (r *Client) AccountUpdate | NICEXAI | +| 获取客服帐号列表 | GET | /cgi-bin/kf/account/list | YES | (r *Client) AccountList | NICEXAI | +| 获取客服帐号链接 | GET | /cgi-bin/kf/add_contact_way | YES | (r *Client) AddContactWay | NICEXAI | ### 接待人员列表 -TODO +[官方文档](https://open.work.weixin.qq.com/api/doc/90001/90143/94693) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 |贡献者 | +| :--------------: | -------- | :-------------------------- | ---------- | -------------------------------|------------| +| 添加接待人员 | POST | /cgi-bin/kf/servicer/add | YES | (r *Client) ReceptionistAdd | NICEXAI | +| 删除接待人员 | POST | /cgi-bin/kf/servicer/del | YES | (r *Client) ReceptionistDel | NICEXAI | +| 获取接待人员列表 | GET | /cgi-bin/kf/servicer/list | YES | (r *Client) ReceptionistList | NICEXAI | ### 会话分配与消息收发 -TODO +[官方文档](https://open.work.weixin.qq.com/api/doc/90001/90143/94694) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 |贡献者 | +| :--------------: | -------- | :-------------------------------| ---------- | ------------------------------- |------------| +| 获取会话状态 | POST | /cgi-bin/kf/service_state/get | YES | (r *Client) ServiceStateGet | NICEXAI | +| 变更会话状态 | POST | /cgi-bin/kf/service_state/trans | YES | (r *Client) ServiceStateTrans | NICEXAI | +| 读取消息 | POST | /cgi-bin/kf/sync_msg | YES | (r *Client) SyncMsg | NICEXAI | +| 发送消息 | POST | /cgi-bin/kf/send_msg | YES | (r *Client) SendMsg | NICEXAI | +| 发送事件响应消息 | POST | /cgi-bin/kf/send_msg_on_event | YES | (r *Client) SendMsgOnEvent | NICEXAI | + +### 升级服务配置 + +[官方文档](https://open.work.weixin.qq.com/api/doc/90001/90143/94702) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 |贡献者 | +| :--------------: | -------- | :-------------------------------------------------| ---------- | ------------------------------- |------------| +| 获取配置的专员与客户群 | POST | /cgi-bin/kf/customer/get_upgrade_service_config | YES | (r *Client) UpgradeServiceConfig | NICEXAI | +| 为客户升级为专员或客户群服务 | POST | /cgi-bin/kf/customer/upgrade_service | YES | (r *Client) UpgradeService | NICEXAI | +| 为客户取消推荐 | POST | /cgi-bin/kf/customer/cancel_upgrade_service | YES | (r *Client) UpgradeServiceCancel | NICEXAI | ### 其他基础信息获取 -TODO +[官方文档](https://open.work.weixin.qq.com/api/doc/90001/90143/95148) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | 贡献者 | +| :--------------: | -------- | :---------------------------------------| ---------- | ------------------------------- |------------| +| 获取客户基础信息 | POST | /cgi-bin/kf/customer/batchget | YES | (r *Client) CustomerBatchGet | NICEXAI | +| 获取视频号绑定状态 | GET | /cgi-bin/kf/get_corp_qualification | YES | (r *Client) GetCorpQualification | NICEXAI | ## 应用管理 From 3fb288d9323c5a86f35003daf79e83b9f5538d70 Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Fri, 8 Oct 2021 19:37:40 +0800 Subject: [PATCH 21/84] =?UTF-8?q?feat:=20=E5=BE=AE=E4=BF=A1=E5=AE=A2?= =?UTF-8?q?=E6=9C=8D=E6=94=AF=E6=8C=81=E5=8F=91=E9=80=81=E6=AC=A2=E8=BF=8E?= =?UTF-8?q?=E8=AF=AD=20(#496)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/kf/sendmsgonevent.go | 13 ++++++++++++- work/kf/syncmsg/message.go | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/work/kf/sendmsgonevent.go b/work/kf/sendmsgonevent.go index 8060d3a..17396df 100644 --- a/work/kf/sendmsgonevent.go +++ b/work/kf/sendmsgonevent.go @@ -19,9 +19,20 @@ type SendMsgOnEventSchema struct { } // SendMsgOnEvent 发送事件响应消息 +// 当特定的事件回调消息包含code字段,或通过接口变更到特定的会话状态,会返回code字段。 +// 开发者可以此code为凭证,调用该接口给用户发送相应事件场景下的消息,如客服欢迎语、客服提示语和会话结束语等。 +// 除”用户进入会话事件”以外,响应消息仅支持会话处于获取该code的会话状态时发送,如将会话转入待接入池时获得的code仅能在会话状态为”待接入池排队中“时发送。 +// +// 目前支持的事件场景和相关约束如下: +// +// 事件场景 允许下发条数 code有效期 支持的消息类型 获取code途径 +// 用户进入会话,用于发送客服欢迎语 1条 20秒 文本、菜单 事件回调 +// 进入接待池,用于发送排队提示语等 1条 48小时 文本 转接会话接口 +// 从接待池接入会话,用于发送非工作时间的提示语或超时未回复的提示语等 1条 48小时 文本 事件回调、转接会话接口 +// 结束会话,用于发送结束会话提示语或满意度评价等 1条 20秒 文本、菜单 事件回调、转接会话接口 +// //「进入会话事件」响应消息: // 如果满足通过API下发欢迎语条件(条件为:1. 企业没有在管理端配置了原生欢迎语;2. 用户在过去48小时里未收过欢迎语,且未向该用户发过消息),则用户进入会话事件会额外返回一个welcome_code,开发者以此为凭据调用接口(填到该接口code参数),即可向客户发送客服欢迎语。 -// 为了保证用户体验以及避免滥用,开发者仅可在收到相关事件后20秒内调用,且只可调用一次。 func (r *Client) SendMsgOnEvent(options interface{}) (info SendMsgOnEventSchema, err error) { var ( accessToken string diff --git a/work/kf/syncmsg/message.go b/work/kf/syncmsg/message.go index d889903..a447b78 100644 --- a/work/kf/syncmsg/message.go +++ b/work/kf/syncmsg/message.go @@ -159,5 +159,6 @@ type SessionStatusChangeEvent struct { ChangeType uint32 `json:"change_type"` // 变更类型。1-从接待池接入会话 2-转接会话 3-结束会话 OldReceptionistUserID string `json:"old_servicer_userid"` // 老的客服人员userid。仅change_type为2和3有值 NewReceptionistUserID string `json:"new_servicer_userid"` // 新的客服人员userid。仅change_type为1和2有值 + MsgCode string `json:"msg_code"` // 用于发送事件响应消息的code,仅change_type为1和3时,会返回该字段。可用该msg_code调用发送事件响应消息接口给客户发送回复语或结束语。 } `json:"event"` // 事件消息 } From efad41bcda80bf0e3dc096f8e9a92865cc295675 Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Mon, 1 Nov 2021 10:07:48 +0800 Subject: [PATCH 22/84] =?UTF-8?q?pref:=20=E4=BC=98=E5=8C=96=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA=20(#503)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/kf/error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/work/kf/error.go b/work/kf/error.go index d4e4474..4cfebd8 100644 --- a/work/kf/error.go +++ b/work/kf/error.go @@ -28,7 +28,7 @@ const ( // SDKDecryptMSGFailed 错误码:40016 SDKDecryptMSGFailed Error = "消息解密失败" // SDKMediaIDExceedMinLength 错误码:40058 - SDKMediaIDExceedMinLength Error = "media_id 小于最小长度 1" + SDKMediaIDExceedMinLength Error = "不合法的参数, 请参照具体 API 接口说明进行传参" // SDKContentContainsSensitiveInformation 错误码:40201 SDKContentContainsSensitiveInformation Error = "当前客服账号由于涉及敏感信息,已被封禁,请联系企业微信客服处理" // SDKAccessTokenMissing 错误码:41001 From 05ec6a42ae555b701f3fe07a29f735fab668d2bc Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Fri, 5 Nov 2021 17:37:27 +0800 Subject: [PATCH 23/84] =?UTF-8?q?docs:=E6=9B=B4=E6=96=B0=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=8F=91=E9=80=81=E9=99=90=E5=88=B6=E8=AF=B4?= =?UTF-8?q?=E6=98=8E=E6=96=87=E6=A1=A3=20(#504)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/kf/sendmsg.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/work/kf/sendmsg.go b/work/kf/sendmsg.go index 2f2049f..053011f 100644 --- a/work/kf/sendmsg.go +++ b/work/kf/sendmsg.go @@ -18,7 +18,14 @@ type SendMsgSchema struct { MsgID string `json:"msgid"` // 消息ID。如果请求参数指定了msgid,则原样返回,否则系统自动生成并返回。不多于32字节, 字符串取值范围(正则表达式):[0-9a-zA-Z_-]* } -// SendMsg 获取消息 +// SendMsg 发送消息 +// 当微信客户处于“新接入待处理”或“由智能助手接待”状态下,可调用该接口给用户发送消息。 +// 注意仅当微信客户在主动发送消息给客服后的48小时内,企业可发送消息给客户,最多可发送5条消息;若用户继续发送消息,企业可再次下发消息。 +// 支持发送消息类型:文本、图片、语音、视频、文件、图文、小程序、菜单消息、地理位置。 +// 目前该接口允许下发消息条数和下发时限如下: +// +// 用户动作 允许下发条数限制 下发时限 +// 用户发送消息 5条 48 小时 func (r *Client) SendMsg(options interface{}) (info SendMsgSchema, err error) { var ( accessToken string From dc24ad4262dcc306297be0497e693420c3bbee57 Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Mon, 15 Nov 2021 17:05:13 +0800 Subject: [PATCH 24/84] =?UTF-8?q?feat:=20=E5=BE=AE=E4=BF=A1=E5=AE=A2?= =?UTF-8?q?=E6=9C=8D=E4=BC=9A=E8=AF=9D=E7=8A=B6=E6=80=81=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E6=97=B6=E6=94=AF=E6=8C=81=E5=8F=91=E9=80=81=E5=9B=9E=E5=A4=8D?= =?UTF-8?q?=E8=AF=AD=20(#505)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/kf/servicestate.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/work/kf/servicestate.go b/work/kf/servicestate.go index 4834838..d14599a 100644 --- a/work/kf/servicestate.go +++ b/work/kf/servicestate.go @@ -64,8 +64,14 @@ type ServiceStateTransOptions struct { ServicerUserID string `json:"servicer_userid"` // 接待人员的userid,当state=3时要求必填,接待人员须处于“正在接待”中 } +// ServiceStateTransSchema 变更会话状态响应内容 +type ServiceStateTransSchema struct { + util.CommonError + MsgCode string `json:"msg_code"` // 用于发送响应事件消息的code,将会话初次变更为service_state为2和3时,返回回复语code,service_state为4时,返回结束语code。可用该code调用发送事件响应消息接口给客户发送事件响应消息 +} + // ServiceStateTrans 变更会话状态 -func (r *Client) ServiceStateTrans(options ServiceStateTransOptions) (info util.CommonError, err error) { +func (r *Client) ServiceStateTrans(options ServiceStateTransOptions) (info ServiceStateTransSchema, err error) { var ( accessToken string data []byte From 566c3c27cbb9721dd9e14d4770841df6089477c4 Mon Sep 17 00:00:00 2001 From: ixugo <59127546+ixugo@users.noreply.github.com> Date: Mon, 15 Nov 2021 17:06:50 +0800 Subject: [PATCH 25/84] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AE=A2=E9=98=85?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E4=BA=8B=E4=BB=B6=20(#509)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- officialaccount/message/message.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/officialaccount/message/message.go b/officialaccount/message/message.go index f6f255f..4635a1e 100644 --- a/officialaccount/message/message.go +++ b/officialaccount/message/message.go @@ -73,6 +73,8 @@ const ( EventMassSendJobFinish = "MASSSENDJOBFINISH" // EventWxaMediaCheck 异步校验图片/音频是否含有违法违规内容推送事件 EventWxaMediaCheck = "wxa_media_check" + // EventSubscribeMsgPopupEvent 订阅通知事件推送 + EventSubscribeMsgPopupEvent = "subscribe_msg_popup_event" ) const ( @@ -144,6 +146,10 @@ type MixMessage struct { Poiname string `xml:"Poiname"` } + SubscribeMsgPopupEvent []struct { + List SubscribeMsgPopupEvent `xml:"List"` + } `xml:"SubscribeMsgPopupEvent"` + // 第三方平台相关 InfoType InfoType `xml:"InfoType"` AppID string `xml:"AppId"` @@ -183,6 +189,13 @@ type MixMessage struct { device.MsgDevice } +// SubscribeMsgPopupEvent 订阅通知事件推送的消息体 +type SubscribeMsgPopupEvent struct { + TemplateID string `xml:"TemplateId"` + SubscribeStatusString string `xml:"SubscribeStatusString"` + PopupScene int `xml:"PopupScene"` +} + // EventPic 发图事件推送 type EventPic struct { PicMd5Sum string `xml:"PicMd5Sum"` From 74053fe6efbfe1f40acbf0716364ac71464a674c Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Mon, 15 Nov 2021 19:16:12 +0800 Subject: [PATCH 26/84] =?UTF-8?q?feat:=20=E5=BE=AE=E4=BF=A1=E5=AE=A2?= =?UTF-8?q?=E6=9C=8D=E4=BC=9A=E8=AF=9D=E5=8F=98=E6=9B=B4=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9F=A5=E7=9C=8B=E5=AE=A2=E6=9C=8D=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7ID=20(#510)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/kf/syncmsg/message.go | 1 + 1 file changed, 1 insertion(+) diff --git a/work/kf/syncmsg/message.go b/work/kf/syncmsg/message.go index a447b78..91aaffc 100644 --- a/work/kf/syncmsg/message.go +++ b/work/kf/syncmsg/message.go @@ -144,6 +144,7 @@ type ReceptionistStatusChangeEvent struct { Event struct { EventType string `json:"event_type"` // 事件类型。此处固定为:servicer_status_change ReceptionistUserID string `json:"servicer_userid"` // 客服人员userid + OpenKFID string `json:"open_kfid"` // 客服帐号ID Status uint32 `json:"status"` // 状态类型。1-接待中 2-停止接待 } `json:"event"` } From 8c87c49f2adcde3feac47929d403383b7fda1c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=88=90=E9=94=B4?= <243852814@qq.com> Date: Fri, 3 Dec 2021 20:45:11 +0800 Subject: [PATCH 27/84] =?UTF-8?q?update:=20=E7=BB=9F=E4=B8=80=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E7=B1=BB=E5=9E=8B=20(#511)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- officialaccount/message/message.go | 60 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/officialaccount/message/message.go b/officialaccount/message/message.go index 4635a1e..9b28639 100644 --- a/officialaccount/message/message.go +++ b/officialaccount/message/message.go @@ -19,62 +19,62 @@ const ( // MsgTypeText 表示文本消息 MsgTypeText MsgType = "text" // MsgTypeImage 表示图片消息 - MsgTypeImage = "image" + MsgTypeImage MsgType = "image" // MsgTypeVoice 表示语音消息 - MsgTypeVoice = "voice" + MsgTypeVoice MsgType = "voice" // MsgTypeVideo 表示视频消息 - MsgTypeVideo = "video" + MsgTypeVideo MsgType = "video" // MsgTypeMiniprogrampage 表示小程序卡片消息 - MsgTypeMiniprogrampage = "miniprogrampage" + MsgTypeMiniprogrampage MsgType = "miniprogrampage" // MsgTypeShortVideo 表示短视频消息[限接收] - MsgTypeShortVideo = "shortvideo" + MsgTypeShortVideo MsgType = "shortvideo" // MsgTypeLocation 表示坐标消息[限接收] - MsgTypeLocation = "location" + MsgTypeLocation MsgType = "location" // MsgTypeLink 表示链接消息[限接收] - MsgTypeLink = "link" + MsgTypeLink MsgType = "link" // MsgTypeMusic 表示音乐消息[限回复] - MsgTypeMusic = "music" + MsgTypeMusic MsgType = "music" // MsgTypeNews 表示图文消息[限回复] - MsgTypeNews = "news" + MsgTypeNews MsgType = "news" // MsgTypeTransfer 表示消息消息转发到客服 - MsgTypeTransfer = "transfer_customer_service" + MsgTypeTransfer MsgType = "transfer_customer_service" // MsgTypeEvent 表示事件推送消息 - MsgTypeEvent = "event" + MsgTypeEvent MsgType = "event" ) const ( // EventSubscribe 订阅 EventSubscribe EventType = "subscribe" // EventUnsubscribe 取消订阅 - EventUnsubscribe = "unsubscribe" + EventUnsubscribe EventType = "unsubscribe" // EventScan 用户已经关注公众号,则微信会将带场景值扫描事件推送给开发者 - EventScan = "SCAN" + EventScan EventType = "SCAN" // EventLocation 上报地理位置事件 - EventLocation = "LOCATION" + EventLocation EventType = "LOCATION" // EventClick 点击菜单拉取消息时的事件推送 - EventClick = "CLICK" + EventClick EventType = "CLICK" // EventView 点击菜单跳转链接时的事件推送 - EventView = "VIEW" + EventView EventType = "VIEW" // EventScancodePush 扫码推事件的事件推送 - EventScancodePush = "scancode_push" + EventScancodePush EventType = "scancode_push" // EventScancodeWaitmsg 扫码推事件且弹出“消息接收中”提示框的事件推送 - EventScancodeWaitmsg = "scancode_waitmsg" + EventScancodeWaitmsg EventType = "scancode_waitmsg" // EventPicSysphoto 弹出系统拍照发图的事件推送 - EventPicSysphoto = "pic_sysphoto" + EventPicSysphoto EventType = "pic_sysphoto" // EventPicPhotoOrAlbum 弹出拍照或者相册发图的事件推送 - EventPicPhotoOrAlbum = "pic_photo_or_album" + EventPicPhotoOrAlbum EventType = "pic_photo_or_album" // EventPicWeixin 弹出微信相册发图器的事件推送 - EventPicWeixin = "pic_weixin" + EventPicWeixin EventType = "pic_weixin" // EventLocationSelect 弹出地理位置选择器的事件推送 - EventLocationSelect = "location_select" + EventLocationSelect EventType = "location_select" // EventTemplateSendJobFinish 发送模板消息推送通知 - EventTemplateSendJobFinish = "TEMPLATESENDJOBFINISH" + EventTemplateSendJobFinish EventType = "TEMPLATESENDJOBFINISH" // EventMassSendJobFinish 群发消息推送通知 - EventMassSendJobFinish = "MASSSENDJOBFINISH" + EventMassSendJobFinish EventType = "MASSSENDJOBFINISH" // EventWxaMediaCheck 异步校验图片/音频是否含有违法违规内容推送事件 - EventWxaMediaCheck = "wxa_media_check" + EventWxaMediaCheck EventType = "wxa_media_check" // EventSubscribeMsgPopupEvent 订阅通知事件推送 - EventSubscribeMsgPopupEvent = "subscribe_msg_popup_event" + EventSubscribeMsgPopupEvent EventType = "subscribe_msg_popup_event" ) const ( @@ -83,13 +83,13 @@ const ( // InfoTypeVerifyTicket 返回ticket InfoTypeVerifyTicket InfoType = "component_verify_ticket" // InfoTypeAuthorized 授权 - InfoTypeAuthorized = "authorized" + InfoTypeAuthorized InfoType = "authorized" // InfoTypeUnauthorized 取消授权 - InfoTypeUnauthorized = "unauthorized" + InfoTypeUnauthorized InfoType = "unauthorized" // InfoTypeUpdateAuthorized 更新授权 - InfoTypeUpdateAuthorized = "updateauthorized" + InfoTypeUpdateAuthorized InfoType = "updateauthorized" // InfoTypeNotifyThirdFasterRegister 注册审核事件推送 - InfoTypeNotifyThirdFasterRegister = "notify_third_fasteregister" + InfoTypeNotifyThirdFasterRegister InfoType = "notify_third_fasteregister" ) // MixMessage 存放所有微信发送过来的消息和事件 From e068d53dcb7ed395f6e14962b40c4c0974739fc3 Mon Sep 17 00:00:00 2001 From: silenceper Date: Mon, 6 Dec 2021 11:19:25 +0800 Subject: [PATCH 28/84] Create release.yml --- .github/workflows/release.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3c97636 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: goreleaser + +on: + push: + tags: + - '*' + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - + name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.15 + - + name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 83e223999bec1b4a9c6fdbd24d0037cebd41c0d9 Mon Sep 17 00:00:00 2001 From: silenceper Date: Mon, 6 Dec 2021 11:32:49 +0800 Subject: [PATCH 29/84] add .goreleaser.yml Signed-off-by: silenceper --- .goreleaser.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .goreleaser.yml diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..a097d09 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,29 @@ +# This is an example goreleaser.yaml file with some sane defaults. +# Make sure to check the documentation at http://goreleaser.com +before: + hooks: + # You may remove this if you don't use go modules. + - go mod download + # you may remove this if you don't need go generate + - go generate ./... +builds: +- skip: true + +archives: + - replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 + +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' From 9cecda04697f0e92602d9cf9efb9b4afd3d47b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=84=8F=E7=90=A6=E8=A1=8C?= <31980412+lixd@users.noreply.github.com> Date: Tue, 7 Dec 2021 19:05:37 +0800 Subject: [PATCH 30/84] =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=A0=81?= =?UTF-8?q?=E3=80=81URL=20Link=20=E5=A2=9E=E5=8A=A0=E5=8F=82=E6=95=B0(#502?= =?UTF-8?q?,#512)=20(#514)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 小程序码、URL Link 增加参数(#502,#512) * gofmt --- miniprogram/qrcode/qrcode.go | 4 ++++ miniprogram/urllink/urllink.go | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/miniprogram/qrcode/qrcode.go b/miniprogram/qrcode/qrcode.go index 3ee3179..5420088 100644 --- a/miniprogram/qrcode/qrcode.go +++ b/miniprogram/qrcode/qrcode.go @@ -40,6 +40,8 @@ type QRCoder struct { Page string `json:"page,omitempty"` // path 扫码进入的小程序页面路径 Path string `json:"path,omitempty"` + // checkPath 检查page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用 + CheckPath bool `json:"check_path,omitempty"` // width 图片宽度 Width int `json:"width,omitempty"` // scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) @@ -50,6 +52,8 @@ type QRCoder struct { LineColor Color `json:"line_color,omitempty"` // isHyaline 是否需要透明底色 IsHyaline bool `json:"is_hyaline,omitempty"` + // envVersion 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop" + EnvVersion string `json:"env_version,omitempty"` } // fetchCode 请求并返回二维码二进制数据 diff --git a/miniprogram/urllink/urllink.go b/miniprogram/urllink/urllink.go index c89aa7e..378d58a 100644 --- a/miniprogram/urllink/urllink.go +++ b/miniprogram/urllink/urllink.go @@ -33,8 +33,10 @@ const ( // ULParams 请求参数 // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html#请求参数 type ULParams struct { - Path string `json:"path"` - Query string `json:"query"` + Path string `json:"path"` + Query string `json:"query"` + // envVersion 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop" + EnvVersion string `json:"env_version,omitempty"` IsExpire bool `json:"is_expire"` ExpireType TExpireType `json:"expire_type"` ExpireTime int64 `json:"expire_time"` From 4721f7567b67a8f25c97b98142a9b483c43765ba Mon Sep 17 00:00:00 2001 From: wby Date: Tue, 28 Dec 2021 14:34:50 +0800 Subject: [PATCH 31/84] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E9=9A=90=E7=A7=81=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=20(#518)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * save * set privacy * 完善小程序隐私设置接口 * fix privacy desc * 移除gitpod定义文件,api响应解析改用公共方法 * use DecodeWithCommonError * fix ci * fix ci * fix other package ci * fix err --- go.mod | 2 +- miniprogram/miniprogram.go | 6 ++ miniprogram/privacy/privacy.go | 167 +++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 miniprogram/privacy/privacy.go diff --git a/go.mod b/go.mod index c091722..cce929f 100644 --- a/go.mod +++ b/go.mod @@ -15,4 +15,4 @@ require ( golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/h2non/gock.v1 v1.0.15 -) \ No newline at end of file +) diff --git a/miniprogram/miniprogram.go b/miniprogram/miniprogram.go index 4ebbe09..af098f0 100644 --- a/miniprogram/miniprogram.go +++ b/miniprogram/miniprogram.go @@ -9,6 +9,7 @@ import ( "github.com/silenceper/wechat/v2/miniprogram/context" "github.com/silenceper/wechat/v2/miniprogram/encryptor" "github.com/silenceper/wechat/v2/miniprogram/message" + "github.com/silenceper/wechat/v2/miniprogram/privacy" "github.com/silenceper/wechat/v2/miniprogram/qrcode" "github.com/silenceper/wechat/v2/miniprogram/shortlink" "github.com/silenceper/wechat/v2/miniprogram/subscribe" @@ -57,6 +58,11 @@ func (miniProgram *MiniProgram) GetAnalysis() *analysis.Analysis { return analysis.NewAnalysis(miniProgram.ctx) } +// GetPrivacy 小程序隐私协议相关API +func (miniProgram *MiniProgram) GetPrivacy() *privacy.Privacy { + return privacy.NewPrivacy(miniProgram.ctx) +} + // GetQRCode 小程序码相关API func (miniProgram *MiniProgram) GetQRCode() *qrcode.QRCode { return qrcode.NewQRCode(miniProgram.ctx) diff --git a/miniprogram/privacy/privacy.go b/miniprogram/privacy/privacy.go new file mode 100644 index 0000000..024e379 --- /dev/null +++ b/miniprogram/privacy/privacy.go @@ -0,0 +1,167 @@ +package privacy + +import ( + "errors" + "fmt" + + "github.com/silenceper/wechat/v2/miniprogram/context" + "github.com/silenceper/wechat/v2/util" +) + +// Privacy 小程序授权隐私设置 +type Privacy struct { + *context.Context +} + +// NewPrivacy 实例化小程序隐私接口 +// 文档地址 https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/privacy_config/set_privacy_setting.html +func NewPrivacy(context *context.Context) *Privacy { + if context == nil { + panic("NewPrivacy got a nil context") + } + return &Privacy{ + context, + } +} + +// OwnerSetting 收集方(开发者)信息配置 +type OwnerSetting struct { + ContactEmail string `json:"contact_email"` + ContactPhone string `json:"contact_phone"` + ContactQQ string `json:"contact_qq"` + ContactWeixin string `json:"contact_weixin"` + ExtFileMediaID string `json:"ext_file_media_id"` + NoticeMethod string `json:"notice_method"` + StoreExpireTimestamp string `json:"store_expire_timestamp"` +} + +// SettingItem 收集权限的配置 +type SettingItem struct { + PrivacyKey string `json:"privacy_key"` + PrivacyText string `json:"privacy_text"` +} + +// SetPrivacySettingRequest 设置权限的请求参数 +type SetPrivacySettingRequest struct { + PrivacyVer int `json:"privacy_ver"` + OwnerSetting OwnerSetting `json:"owner_setting"` + SettingList []SettingItem `json:"setting_list"` +} + +const ( + setPrivacySettingURL = "https://api.weixin.qq.com/cgi-bin/component/setprivacysetting" + getPrivacySettingURL = "https://api.weixin.qq.com/cgi-bin/component/getprivacysetting" + uploadPrivacyExtFileURL = "https://api.weixin.qq.com/cgi-bin/component/uploadprivacyextfile" + + // PrivacyV1 用户隐私保护指引的版本,1表示现网版本。 + PrivacyV1 = 1 + // PrivacyV2 2表示开发版。默认是2开发版。 + PrivacyV2 = 2 +) + +// GetPrivacySettingResponse 获取权限配置的响应结果 +type GetPrivacySettingResponse struct { + util.CommonError + CodeExist int `json:"code_exist"` + PrivacyList []string `json:"privacy_list"` + SettingList []SettingResponseItem `json:"setting_list"` + UpdateTime int64 `json:"update_time"` + OwnerSetting OwnerSetting `json:"owner_setting"` + PrivacyDesc DescList `json:"privacy_desc"` +} + +// SettingResponseItem 获取权限设置的响应明细 +type SettingResponseItem struct { + PrivacyKey string `json:"privacy_key"` + PrivacyText string `json:"privacy_text"` + PrivacyLabel string `json:"privacy_label"` +} + +// DescList 权限列表(保持与官方一致) +type DescList struct { + PrivacyDescList []Desc `json:"privacy_desc_list"` +} + +// Desc 权限列表明细(保持与官方一致) +type Desc struct { + PrivacyDesc string `json:"privacy_desc"` + PrivacyKey string `json:"privacy_key"` +} + +// GetPrivacySetting 获取小程序权限配置 +func (s *Privacy) GetPrivacySetting(privacyVer int) (GetPrivacySettingResponse, error) { + accessToken, err := s.GetAccessToken() + if err != nil { + return GetPrivacySettingResponse{}, err + } + + response, err := util.PostJSON(fmt.Sprintf("%s?access_token=%s", getPrivacySettingURL, accessToken), map[string]int{ + "privacy_ver": privacyVer, + }) + if err != nil { + return GetPrivacySettingResponse{}, err + } + // 返回错误信息 + var result GetPrivacySettingResponse + if err = util.DecodeWithError(response, &result, "getprivacysetting"); err != nil { + return GetPrivacySettingResponse{}, err + } + + return result, nil +} + +// SetPrivacySetting 更新小程序权限配置 +func (s *Privacy) SetPrivacySetting(privacyVer int, ownerSetting OwnerSetting, settingList []SettingItem) error { + if privacyVer == PrivacyV1 && len(settingList) > 0 { + return errors.New("当privacy_ver传2或者不传时,setting_list是必填;当privacy_ver传1时,该参数不可传") + } + accessToken, err := s.GetAccessToken() + if err != nil { + return err + } + + response, err := util.PostJSON(fmt.Sprintf("%s?access_token=%s", setPrivacySettingURL, accessToken), SetPrivacySettingRequest{ + PrivacyVer: privacyVer, + OwnerSetting: ownerSetting, + SettingList: settingList, + }) + if err != nil { + return err + } + + // 返回错误信息 + if err = util.DecodeWithCommonError(response, "setprivacysetting"); err != nil { + return err + } + + return err +} + +// UploadPrivacyExtFileResponse 上传权限定义模板响应参数 +type UploadPrivacyExtFileResponse struct { + util.CommonError + ExtFileMediaID string `json:"ext_file_media_id"` +} + +// UploadPrivacyExtFile 上传权限定义模板 +func (s *Privacy) UploadPrivacyExtFile(fileData []byte) (UploadPrivacyExtFileResponse, error) { + accessToken, err := s.GetAccessToken() + if err != nil { + return UploadPrivacyExtFileResponse{}, err + } + + response, err := util.PostJSON(fmt.Sprintf("%s?access_token=%s", uploadPrivacyExtFileURL, accessToken), map[string][]byte{ + "file": fileData, + }) + if err != nil { + return UploadPrivacyExtFileResponse{}, err + } + + // 返回错误信息 + var result UploadPrivacyExtFileResponse + if err = util.DecodeWithError(response, &result, "setprivacysetting"); err != nil { + return UploadPrivacyExtFileResponse{}, err + } + + return result, err +} From 2f898f80f6115ca61f55fae4d18ec37f6d4c1458 Mon Sep 17 00:00:00 2001 From: silenceper Date: Fri, 31 Dec 2021 11:35:05 +0800 Subject: [PATCH 32/84] fix SdkFileID (#520) --- work/msgaudit/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/work/msgaudit/README.md b/work/msgaudit/README.md index 28068b9..9d4a4b2 100644 --- a/work/msgaudit/README.md +++ b/work/msgaudit/README.md @@ -64,7 +64,7 @@ func main() { if chatInfo.Type == "image" { image, _ := chatInfo.GetImageMessage() - sdkfileid := image.Image.SdkFileId + sdkfileid := image.Image.SdkFileID isFinish := false buffer := bytes.Buffer{} From 172c4abde5c4b50153d24ff61fb3a0b97ec697a0 Mon Sep 17 00:00:00 2001 From: zxr615 <30486360+zxr615@users.noreply.github.com> Date: Wed, 5 Jan 2022 09:13:25 +0800 Subject: [PATCH 33/84] =?UTF-8?q?=E9=80=9A=E8=BF=87component=5Fverify=5Fti?= =?UTF-8?q?cket=20=E8=8E=B7=E5=8F=96=20ComponentAccessToken=20=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=A4=84=E7=90=86=20(#521)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openplatform/context/accessToken.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openplatform/context/accessToken.go b/openplatform/context/accessToken.go index 7e42ed7..03bbbbf 100644 --- a/openplatform/context/accessToken.go +++ b/openplatform/context/accessToken.go @@ -26,6 +26,7 @@ const ( // ComponentAccessToken 第三方平台 type ComponentAccessToken struct { + util.CommonError AccessToken string `json:"component_access_token"` ExpiresIn int64 `json:"expires_in"` } @@ -57,6 +58,10 @@ func (ctx *Context) SetComponentAccessToken(verifyTicket string) (*ComponentAcce return nil, err } + if at.ErrCode != 0 { + return nil, fmt.Errorf("SetComponentAccessToken Error , errcode=%d , errmsg=%s", at.ErrCode, at.ErrMsg) + } + accessTokenCacheKey := fmt.Sprintf("component_access_token_%s", ctx.AppID) expires := at.ExpiresIn - 1500 if err := ctx.Cache.Set(accessTokenCacheKey, at.AccessToken, time.Duration(expires)*time.Second); err != nil { From 0d915d203bc1370e85e068aa3d3a6409c456729b Mon Sep 17 00:00:00 2001 From: Afeyer <1500527791@qq.com> Date: Sun, 9 Jan 2022 13:02:48 +0800 Subject: [PATCH 34/84] =?UTF-8?q?docs:=E6=9B=B4=E6=96=B0=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E5=AD=98=E6=A1=A3README.md=E6=96=87=E4=BB=B6=E5=86=85=E7=9A=84?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81=20(#527)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work/msgaudit/README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/work/msgaudit/README.md b/work/msgaudit/README.md index 9d4a4b2..3595500 100644 --- a/work/msgaudit/README.md +++ b/work/msgaudit/README.md @@ -34,13 +34,13 @@ import ( func main() { //初始化客户端 wechatClient := wechat.NewWechat() - + workClient := wechatClient.GetWork(&config.Config{ CorpID: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", CorpSecret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", RasPrivateKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", }) - + client, err := workClient.GetMsgAudit() if err != nil { fmt.Printf("SDK 初始化失败:%v \n", err) @@ -64,13 +64,14 @@ func main() { if chatInfo.Type == "image" { image, _ := chatInfo.GetImageMessage() - sdkfileid := image.Image.SdkFileID + sdkFileID := image.Image.SdkFileID isFinish := false buffer := bytes.Buffer{} + indexBuf := "" for !isFinish { //获取媒体数据 - mediaData, err := client.GetMediaData("", sdkfileid, "", "", 5) + mediaData, err := client.GetMediaData(indexBuf, sdkFileID, "", "", 5) if err != nil { fmt.Printf("媒体数据拉取失败:%v \n", err) return @@ -79,6 +80,7 @@ func main() { if mediaData.IsFinish { isFinish = mediaData.IsFinish } + indexBuf = mediaData.OutIndexBuf } filePath, _ := os.Getwd() filePath = path.Join(filePath, "test.png") @@ -90,11 +92,11 @@ func main() { break } } - + //释放SDK实例 client.Free() } -``` +``` \ No newline at end of file From 80ce4aefc4684c8c8d920d3528dc14f1c5f9fc2b Mon Sep 17 00:00:00 2001 From: wby Date: Tue, 11 Jan 2022 18:22:07 +0800 Subject: [PATCH 35/84] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E6=96=B0=E7=89=88=E8=8E=B7=E5=8F=96=E6=89=8B=E6=9C=BA?= =?UTF-8?q?=E5=8F=B7=E6=8E=88=E6=9D=83=E6=8E=A5=E5=8F=A3=20(#528)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/auth/auth.go | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/miniprogram/auth/auth.go b/miniprogram/auth/auth.go index 084bd92..6420480 100644 --- a/miniprogram/auth/auth.go +++ b/miniprogram/auth/auth.go @@ -13,6 +13,8 @@ const ( code2SessionURL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code" checkEncryptedDataURL = "https://api.weixin.qq.com/wxa/business/checkencryptedmsg?access_token=%s" + + getPhoneNumber = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s" ) // Auth 登录/用户信息 @@ -90,3 +92,42 @@ func (auth *Auth) CheckEncryptedDataContext(ctx context2.Context, encryptedMsgHa } return } + +// GetPhoneNumberResponse 新版获取用户手机号响应结构体 +type GetPhoneNumberResponse struct { + util.CommonError + + PhoneInfo PhoneInfo `json:"phone_info"` +} + +// PhoneInfo 获取用户手机号内容 +type PhoneInfo struct { + PhoneNumber string `json:"phoneNumber"` // 用户绑定的手机号 + PurePhoneNumber string `json:"purePhoneNumber"` // 没有区号的手机号 + CountryCode string `json:"countryCode"` // 区号 + WaterMark struct { + Timestamp int64 `json:"timestamp"` + AppID string `json:"appid"` + } `json:"watermark"` // 数据水印 +} + +// GetPhoneNumber 小程序通过code获取用户手机号 +func (auth *Auth) GetPhoneNumber(code string) (result GetPhoneNumberResponse, err error) { + var response []byte + var ( + at string + ) + if at, err = auth.GetAccessToken(); err != nil { + return + } + body := map[string]interface{}{ + "code": code, + } + if response, err = util.PostJSON(fmt.Sprintf(getPhoneNumber, at), body); err != nil { + return + } + if err = util.DecodeWithError(response, &result, "phonenumber.getPhoneNumber"); err != nil { + return + } + return +} From 5c4b28acee44faeb2743610ad904c249ee95979f Mon Sep 17 00:00:00 2001 From: save95 <3973008+save95@users.noreply.github.com> Date: Mon, 14 Feb 2022 10:19:55 +0800 Subject: [PATCH 36/84] =?UTF-8?q?add:=20=E5=A2=9E=E5=8A=A0=E5=85=AC?= =?UTF-8?q?=E4=BC=97=E5=8F=B7=E3=80=8C=E5=8F=91=E5=B8=83=E8=83=BD=E5=8A=9B?= =?UTF-8?q?=E3=80=8D=E6=8E=A5=E5=8F=A3=EF=BC=88#530=EF=BC=89=20(#531)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add: 增加公众号「发布能力」接口(#530) * fix: go lint * fix: 修复响应结构体及解析方式 * add: 增加公众号「草稿箱」接口(#530) * fix: text * mod: 增加 发布任务完成 消息事件 Co-authored-by: luoyu --- doc/api/officialaccount.md | 39 ++++ officialaccount/draft/draft.go | 228 +++++++++++++++++++ officialaccount/freepublish/freepublish.go | 248 +++++++++++++++++++++ officialaccount/message/message.go | 18 ++ officialaccount/officialaccount.go | 12 + 5 files changed, 545 insertions(+) create mode 100644 officialaccount/draft/draft.go create mode 100644 officialaccount/freepublish/freepublish.go diff --git a/doc/api/officialaccount.md b/doc/api/officialaccount.md index b1d2543..4631c61 100644 --- a/doc/api/officialaccount.md +++ b/doc/api/officialaccount.md @@ -132,6 +132,8 @@ #### 群发任务管理 +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Shopping_Guide/task-account/shopping-guide.addGuideMassendJob.html) + | 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | | -------------------- | -------- | ------------------------------------- | ---------- | -------- | | 添加群发任务 | POST | /cgi-bin/guide/addguidemassendjob | NO | | @@ -156,6 +158,43 @@ ## 素材管理 +## 草稿箱 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Add_draft.html) + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| -------------------------- | -------- | ------------------------------------------------------------ | ---------- | ---------------------------- | +| 新建草稿 | POST | /cgi-bin/draft/add | YES | (draft *Draft) AddDraft | +| 获取草稿 | POST | /cgi-bin/draft/get | YES | (draft *Draft) GetDraft | +| 删除草稿 | POST | /cgi-bin/draft/delete | YES | (draft *Draft) DeleteDraft | +| 修改草稿 | POST | /cgi-bin/draft/update | YES | (draft *Draft) UpdateDraft | +| 获取草稿总数 | GET | /cgi-bin/draft/count | YES | (draft *Draft) CountDraft | +| 获取草稿列表 | POST | /cgi-bin/draft/batchget | YES | (draft *Draft) PaginateDraft | +| MP端开关(仅内测期间使用) | POST | /cgi-bin/draft/switch
/cgi-bin/draft/switch?checkonly=1 | NO | | + + + +## 发布能力 + +[官方文档](https://developers.weixin.qq.com/doc/offiaccount/Publish/Publish.html) + +说明:「发表记录」包括群发和发布。 + +注意:该接口,只能处理 "发布" 相关的信息,无法操作和获取 "群发" 相关内容!![官方回复](https://developers.weixin.qq.com/community/develop/doc/0002a4fb2109d8f7a91d421c556c00) + +- 群发:主动推送给粉丝,历史消息可看,被搜一搜收录,可以限定部分的粉丝接收到。 +- 发布:不会主动推给粉丝,历史消息列表看不到,但是是公开给所有人的文章。也不会占用群发的次数。每天可以发布多篇内容。可以用于自动回复、自定义菜单、页面模板和话题中,发布成功时会生成一个永久链接。 + +| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | +| ------------------------------ | -------- | ------------------------------- | ---------- | --------------------------------------- | +| 发布接口 | POST | /cgi-bin/freepublish/submit | YES | (freePublish *FreePublish) Publish | +| 发布状态轮询接口 | POST | /cgi-bin/freepublish/get | YES | (freePublish *FreePublish) SelectStatus | +| 事件推送发布结果 | | | YES | EventPublishJobFinish | +| 删除发布 | POST | /cgi-bin/freepublish/delete | YES | (freePublish *FreePublish) Delete | +| 通过 article_id 获取已发布文章 | POST | /cgi-bin/freepublish/getarticle | YES | (freePublish *FreePublish) First | +| 获取成功发布列表 | POST | /cgi-bin/freepublish/batchget | YES | (freePublish *FreePublish) Paginate | + + ## 图文消息留言管理 ## 用户管理 diff --git a/officialaccount/draft/draft.go b/officialaccount/draft/draft.go new file mode 100644 index 0000000..e7f15d3 --- /dev/null +++ b/officialaccount/draft/draft.go @@ -0,0 +1,228 @@ +package draft + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/officialaccount/context" + "github.com/silenceper/wechat/v2/util" +) + +const ( + addURL = "https://api.weixin.qq.com/cgi-bin/draft/add" // 新建草稿 + getURL = "https://api.weixin.qq.com/cgi-bin/draft/get" // 获取草稿 + deleteURL = "https://api.weixin.qq.com/cgi-bin/draft/delete" // 删除草稿 + updateURL = "https://api.weixin.qq.com/cgi-bin/draft/update" // 修改草稿 + countURL = "https://api.weixin.qq.com/cgi-bin/draft/count" // 获取草稿总数 + paginateURL = "https://api.weixin.qq.com/cgi-bin/draft/batchget" // 获取草稿列表 +) + +// Draft 草稿箱 +type Draft struct { + *context.Context +} + +// NewDraft init +func NewDraft(ctx *context.Context) *Draft { + return &Draft{ + Context: ctx, + } +} + +// Article 草稿 +type Article struct { + Title string `json:"title"` // 标题 + Author string `json:"author"` // 作者 + Digest string `json:"digest"` // 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空。 + Content string `json:"content"` // 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且去除JS + ContentSourceURL string `json:"content_source_url"` // 图文消息的原文地址,即点击“阅读原文”后的URL + ThumbMediaID string `json:"thumb_media_id"` // 图文消息的封面图片素材id(必须是永久MediaID) + ShowCoverPic uint `json:"show_cover_pic"` // 是否显示封面,0为false,即不显示,1为true,即显示(默认) + NeedOpenComment uint `json:"need_open_comment"` // 是否打开评论,0不打开(默认),1打开 + OnlyFansCanComment uint `json:"only_fans_can_comment"` // 是否粉丝才可评论,0所有人可评论(默认),1粉丝才可评论 +} + +// AddDraft 新建草稿 +func (draft *Draft) AddDraft(articles []*Article) (mediaID string, err error) { + accessToken, err := draft.GetAccessToken() + if err != nil { + return + } + + var req struct { + Articles []*Article `json:"articles"` + } + req.Articles = articles + + uri := fmt.Sprintf("%s?access_token=%s", addURL, accessToken) + response, err := util.PostJSON(uri, req) + if err != nil { + return + } + + var res struct { + util.CommonError + MediaID string `json:"media_id"` + } + err = util.DecodeWithError(response, &res, "AddDraft") + if err != nil { + return + } + mediaID = res.MediaID + return +} + +// GetDraft 获取草稿 +func (draft *Draft) GetDraft(mediaID string) (articles []*Article, err error) { + accessToken, err := draft.GetAccessToken() + if err != nil { + return + } + + var req struct { + MediaID string `json:"media_id"` + } + req.MediaID = mediaID + + uri := fmt.Sprintf("%s?access_token=%s", getURL, accessToken) + response, err := util.PostJSON(uri, req) + if err != nil { + return + } + + var res struct { + util.CommonError + NewsItem []*Article `json:"news_item"` + } + err = util.DecodeWithError(response, &res, "GetDraft") + if err != nil { + return + } + + articles = res.NewsItem + return +} + +// DeleteDraft 删除草稿 +func (draft *Draft) DeleteDraft(mediaID string) (err error) { + accessToken, err := draft.GetAccessToken() + if err != nil { + return + } + + var req struct { + MediaID string `json:"media_id"` + } + req.MediaID = mediaID + + var response []byte + uri := fmt.Sprintf("%s?access_token=%s", deleteURL, accessToken) + response, err = util.PostJSON(uri, req) + if err != nil { + return + } + + err = util.DecodeWithCommonError(response, "DeleteDraft") + return +} + +// UpdateDraft 修改草稿 +// index 要更新的文章在图文消息中的位置(多图文消息时,此字段才有意义),第一篇为0 +func (draft *Draft) UpdateDraft(article *Article, mediaID string, index uint) (err error) { + accessToken, err := draft.GetAccessToken() + if err != nil { + return + } + + var req struct { + MediaID string `json:"media_id"` + Index uint `json:"index"` + Article *Article `json:"articles"` + } + req.MediaID = mediaID + req.Index = index + req.Article = article + + uri := fmt.Sprintf("%s?access_token=%s", updateURL, accessToken) + var response []byte + response, err = util.PostJSON(uri, req) + if err != nil { + return + } + + err = util.DecodeWithCommonError(response, "UpdateDraft") + return +} + +// CountDraft 获取草稿总数 +func (draft *Draft) CountDraft() (total uint, err error) { + accessToken, err := draft.GetAccessToken() + if err != nil { + return + } + + var response []byte + uri := fmt.Sprintf("%s?access_token=%s", countURL, accessToken) + response, err = util.HTTPGet(uri) + if err != nil { + return + } + + var res struct { + util.CommonError + Total uint `json:"total_count"` + } + err = util.DecodeWithError(response, &res, "CountDraft") + if nil != err { + return + } + + total = res.Total + return +} + +// ArticleList 草稿列表 +type ArticleList struct { + util.CommonError + TotalCount int64 `json:"total_count"` // 草稿素材的总数 + ItemCount int64 `json:"item_count"` // 本次调用获取的素材的数量 + Item []ArticleListItem `json:"item"` +} + +// ArticleListItem 用于 ArticleList 的 item 节点 +type ArticleListItem struct { + MediaID string `json:"media_id"` // 图文消息的id + Content ArticleListContent `json:"content"` // 内容 + UpdateTime int64 `json:"update_time"` // 这篇图文消息素材的最后更新时间 +} + +// ArticleListContent 用于 ArticleListItem 的 content 节点 +type ArticleListContent struct { + NewsItem []Article `json:"news_item"` // 这篇图文消息素材的内容 +} + +// PaginateDraft 获取草稿列表 +func (draft *Draft) PaginateDraft(offset, count int64, noReturnContent bool) (list ArticleList, err error) { + accessToken, err := draft.GetAccessToken() + if err != nil { + return + } + + var req struct { + Count int64 `json:"count"` + Offset int64 `json:"offset"` + NoReturnContent bool `json:"no_content"` + } + req.Count = count + req.Offset = offset + req.NoReturnContent = noReturnContent + + var response []byte + uri := fmt.Sprintf("%s?access_token=%s", paginateURL, accessToken) + response, err = util.PostJSON(uri, req) + if err != nil { + return + } + + err = util.DecodeWithError(response, &list, "PaginateDraft") + return +} diff --git a/officialaccount/freepublish/freepublish.go b/officialaccount/freepublish/freepublish.go new file mode 100644 index 0000000..041bf66 --- /dev/null +++ b/officialaccount/freepublish/freepublish.go @@ -0,0 +1,248 @@ +package freepublish + +import ( + "fmt" + + "github.com/silenceper/wechat/v2/officialaccount/context" + "github.com/silenceper/wechat/v2/util" +) + +const ( + publishURL = "https://api.weixin.qq.com/cgi-bin/freepublish/submit" // 发布接口 + selectStateURL = "https://api.weixin.qq.com/cgi-bin/freepublish/get" // 发布状态轮询接口 + deleteURL = "https://api.weixin.qq.com/cgi-bin/freepublish/delete" // 删除发布 + firstArticleURL = "https://api.weixin.qq.com/cgi-bin/freepublish/getarticle" // 通过 article_id 获取已发布文章 + paginateURL = "https://api.weixin.qq.com/cgi-bin/freepublish/batchget" // 获取成功发布列表 +) + +// PublishStatus 发布状态 +type PublishStatus uint + +const ( + // PublishStatusSuccess 0:成功 + PublishStatusSuccess PublishStatus = iota + // PublishStatusPublishing 1:发布中 + PublishStatusPublishing + // PublishStatusOriginalFail 2:原创失败 + PublishStatusOriginalFail + // PublishStatusFail 3:常规失败 + PublishStatusFail + // PublishStatusAuditRefused 4:平台审核不通过 + PublishStatusAuditRefused + // PublishStatusUserDeleted 5:成功后用户删除所有文章 + PublishStatusUserDeleted + // PublishStatusSystemBanned 6:成功后系统封禁所有文章 + PublishStatusSystemBanned +) + +// FreePublish 发布能力 +type FreePublish struct { + *context.Context +} + +// NewFreePublish init +func NewFreePublish(ctx *context.Context) *FreePublish { + return &FreePublish{ + Context: ctx, + } +} + +// Publish 发布接口。需要先将图文素材以草稿的形式保存(见“草稿箱/新建草稿”, +// 如需从已保存的草稿中选择,见“草稿箱/获取草稿列表”),选择要发布的草稿 media_id 进行发布 +func (freePublish *FreePublish) Publish(mediaID string) (publishID int64, err error) { + var accessToken string + accessToken, err = freePublish.GetAccessToken() + if err != nil { + return + } + + var req struct { + MediaID string `json:"media_id"` + } + req.MediaID = mediaID + + var response []byte + uri := fmt.Sprintf("%s?access_token=%s", publishURL, accessToken) + response, err = util.PostJSON(uri, req) + if err != nil { + return + } + + var res struct { + util.CommonError + PublishID int64 `json:"publish_id"` + } + err = util.DecodeWithError(response, &res, "SubmitFreePublish") + if err != nil { + return + } + + publishID = res.PublishID + return +} + +// PublishStatusList 发布任务状态列表 +type PublishStatusList struct { + util.CommonError + PublishID int64 `json:"publish_id"` // 发布任务id + PublishStatus PublishStatus `json:"publish_status"` // 发布状态 + ArticleID string `json:"article_id"` // 当发布状态为0时(即成功)时,返回图文的 article_id,可用于“客服消息”场景 + ArticleDetail PublishArticleDetail `json:"article_detail"` // 发布任务文章成功状态详情 + FailIndex []uint `json:"fail_idx"` // 当发布状态为2或4时,返回不通过的文章编号,第一篇为 1;其他发布状态则为空 +} + +// PublishArticleDetail 发布任务成功详情 +type PublishArticleDetail struct { + Count uint `json:"count"` // 当发布状态为0时(即成功)时,返回文章数量 + Items []PublishArticleItem `json:"item"` +} + +// PublishArticleItem 发布任务成功的文章内容 +type PublishArticleItem struct { + Index uint `json:"idx"` // 当发布状态为0时(即成功)时,返回文章对应的编号 + ArticleURL string `json:"article_url"` // 当发布状态为0时(即成功)时,返回图文的永久链接 +} + +// SelectStatus 发布状态轮询接口 +func (freePublish *FreePublish) SelectStatus(publishID int64) (list PublishStatusList, err error) { + accessToken, err := freePublish.GetAccessToken() + if err != nil { + return + } + + var req struct { + PublishID int64 `json:"publish_id"` + } + req.PublishID = publishID + + var response []byte + uri := fmt.Sprintf("%s?access_token=%s", selectStateURL, accessToken) + response, err = util.PostJSON(uri, req) + if err != nil { + return + } + + err = util.DecodeWithError(response, &list, "SelectStatusFreePublish") + return +} + +// Delete 删除发布。 +// index 要删除的文章在图文消息中的位置,第一篇编号为1,该字段不填或填0会删除全部文章 +// !!!此操作不可逆,请谨慎操作!!!删除后微信公众号后台仍然会有记录!!! +func (freePublish *FreePublish) Delete(articleID string, index uint) (err error) { + accessToken, err := freePublish.GetAccessToken() + if err != nil { + return err + } + + var req struct { + ArticleID string `json:"article_id"` + Index uint `json:"index"` + } + req.ArticleID = articleID + req.Index = index + + var response []byte + uri := fmt.Sprintf("%s?access_token=%s", deleteURL, accessToken) + response, err = util.PostJSON(uri, req) + if err != nil { + return err + } + + return util.DecodeWithCommonError(response, "DeleteFreePublish") +} + +// Article 图文信息内容 +type Article struct { + Title string `json:"title"` // 标题 + Author string `json:"author"` // 作者 + Digest string `json:"digest"` // 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空 + Content string `json:"content"` // 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS + ContentSourceURL string `json:"content_source_url"` // 图文消息的原文地址,即点击“阅读原文”后的URL + ThumbMediaID string `json:"thumb_media_id"` // 图文消息的封面图片素材id(一定是永久MediaID) + ShowCoverPic uint `json:"show_cover_pic"` // 是否显示封面,0为false,即不显示,1为true,即显示(默认) + NeedOpenComment uint `json:"need_open_comment"` // 是否打开评论,0不打开(默认),1打开 + OnlyFansCanComment uint `json:"only_fans_can_comment"` // 是否粉丝才可评论,0所有人可评论(默认),1粉丝才可评论 + URL string `json:"url"` // 图文消息的URL + IsDeleted bool `json:"is_deleted"` // 该图文是否被删除 +} + +// First 通过 article_id 获取已发布文章 +func (freePublish *FreePublish) First(articleID string) (list []Article, err error) { + accessToken, err := freePublish.GetAccessToken() + if err != nil { + return + } + + var req struct { + ArticleID string `json:"article_id"` + } + req.ArticleID = articleID + + var response []byte + uri := fmt.Sprintf("%s?access_token=%s", firstArticleURL, accessToken) + response, err = util.PostJSON(uri, req) + if err != nil { + return + } + + var res struct { + util.CommonError + NewsItem []Article `json:"news_item"` + } + err = util.DecodeWithError(response, &res, "FirstFreePublish") + if err != nil { + return + } + + list = res.NewsItem + return +} + +// ArticleList 发布列表 +type ArticleList struct { + util.CommonError + TotalCount int64 `json:"total_count"` // 成功发布素材的总数 + ItemCount int64 `json:"item_count"` // 本次调用获取的素材的数量 + Item []ArticleListItem `json:"item"` +} + +// ArticleListItem 用于 ArticleList 的 item 节点 +type ArticleListItem struct { + ArticleID string `json:"article_id"` // 成功发布的图文消息id + Content ArticleListContent `json:"content"` // 内容 + UpdateTime int64 `json:"update_time"` // 这篇图文消息素材的最后更新时间 +} + +// ArticleListContent 用于 ArticleListItem 的 content 节点 +type ArticleListContent struct { + NewsItem []Article `json:"news_item"` // 这篇图文消息素材的内容 +} + +// Paginate 获取成功发布列表 +func (freePublish *FreePublish) Paginate(offset, count int64, noReturnContent bool) (list ArticleList, err error) { + var accessToken string + accessToken, err = freePublish.GetAccessToken() + if err != nil { + return + } + + var req struct { + Count int64 `json:"count"` + Offset int64 `json:"offset"` + NoReturnContent bool `json:"no_content"` + } + req.Count = count + req.Offset = offset + req.NoReturnContent = noReturnContent + + var response []byte + uri := fmt.Sprintf("%s?access_token=%s", paginateURL, accessToken) + response, err = util.PostJSON(uri, req) + if err != nil { + return + } + + err = util.DecodeWithError(response, &list, "PaginateFreePublish") + return +} diff --git a/officialaccount/message/message.go b/officialaccount/message/message.go index 9b28639..841f22f 100644 --- a/officialaccount/message/message.go +++ b/officialaccount/message/message.go @@ -4,6 +4,7 @@ import ( "encoding/xml" "github.com/silenceper/wechat/v2/officialaccount/device" + "github.com/silenceper/wechat/v2/officialaccount/freepublish" ) // MsgType 基本消息类型 @@ -75,6 +76,8 @@ const ( EventWxaMediaCheck EventType = "wxa_media_check" // EventSubscribeMsgPopupEvent 订阅通知事件推送 EventSubscribeMsgPopupEvent EventType = "subscribe_msg_popup_event" + // EventPublishJobFinish 发布任务完成 + EventPublishJobFinish EventType = "PUBLISHJOBFINISH" ) const ( @@ -150,6 +153,21 @@ type MixMessage struct { List SubscribeMsgPopupEvent `xml:"List"` } `xml:"SubscribeMsgPopupEvent"` + // 事件相关:发布能力 + PublishEventInfo struct { + PublishID int64 `xml:"publish_id"` // 发布任务id + PublishStatus freepublish.PublishStatus `xml:"publish_status"` // 发布状态 + ArticleID string `xml:"article_id"` // 当发布状态为0时(即成功)时,返回图文的 article_id,可用于“客服消息”场景 + ArticleDetail struct { + Count uint `xml:"count"` // 文章数量 + Item []struct { + Index uint `xml:"idx"` // 文章对应的编号 + ArticleURL string `xml:"article_url"` // 图文的永久链接 + } `xml:"item"` + } `xml:"article_detail"` // 当发布状态为0时(即成功)时,返回内容 + FailIndex []uint `xml:"fail_idx"` // 当发布状态为2或4时,返回不通过的文章编号,第一篇为 1;其他发布状态则为空 + } `xml:"PublishEventInfo"` + // 第三方平台相关 InfoType InfoType `xml:"InfoType"` AppID string `xml:"AppId"` diff --git a/officialaccount/officialaccount.go b/officialaccount/officialaccount.go index 5697312..3aecce8 100644 --- a/officialaccount/officialaccount.go +++ b/officialaccount/officialaccount.go @@ -3,6 +3,8 @@ package officialaccount import ( "net/http" + "github.com/silenceper/wechat/v2/officialaccount/draft" + "github.com/silenceper/wechat/v2/officialaccount/freepublish" "github.com/silenceper/wechat/v2/officialaccount/ocr" "github.com/silenceper/wechat/v2/officialaccount/datacube" @@ -80,6 +82,16 @@ func (officialAccount *OfficialAccount) GetMaterial() *material.Material { return material.NewMaterial(officialAccount.ctx) } +// GetDraft 草稿箱 +func (officialAccount *OfficialAccount) GetDraft() *draft.Draft { + return draft.NewDraft(officialAccount.ctx) +} + +// GetFreePublish 发布能力 +func (officialAccount *OfficialAccount) GetFreePublish() *freepublish.FreePublish { + return freepublish.NewFreePublish(officialAccount.ctx) +} + // GetJs js-sdk配置 func (officialAccount *OfficialAccount) GetJs() *js.Js { return js.NewJs(officialAccount.ctx) From 1b5c5fba67acc9b934a06348013e406bfef31eea Mon Sep 17 00:00:00 2001 From: lyj <2457395722@qq.com> Date: Mon, 28 Feb 2022 10:38:46 +0800 Subject: [PATCH 37/84] =?UTF-8?q?Bug=20fix:=20`omitempty`=E5=85=B3?= =?UTF-8?q?=E9=94=AE=E5=AD=97=EF=BC=8C=E7=BB=99=E5=AE=83=E8=B5=8B=E7=9A=84?= =?UTF-8?q?=E5=80=BC=E6=81=B0=E5=A5=BD=E7=AD=89=E4=BA=8E=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E7=A9=BA=E5=80=BC=E7=9A=84=E8=AF=9D=EF=BC=8C=E5=9C=A8=E8=BD=AC?= =?UTF-8?q?=E4=B8=BA=20json=20=E4=B9=8B=E5=90=8E=E4=B9=9F=E4=B8=8D?= =?UTF-8?q?=E4=BC=9A=E8=BE=93=E5=87=BA=E8=BF=99=E4=B8=AA=20field=20(#539)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/qrcode/qrcode.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/miniprogram/qrcode/qrcode.go b/miniprogram/qrcode/qrcode.go index 5420088..41e67e5 100644 --- a/miniprogram/qrcode/qrcode.go +++ b/miniprogram/qrcode/qrcode.go @@ -40,17 +40,17 @@ type QRCoder struct { Page string `json:"page,omitempty"` // path 扫码进入的小程序页面路径 Path string `json:"path,omitempty"` - // checkPath 检查page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用 - CheckPath bool `json:"check_path,omitempty"` + // checkPath 检查page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用,默认true + CheckPath *bool `json:"check_path,omitempty"` // width 图片宽度 Width int `json:"width,omitempty"` // scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) Scene string `json:"scene,omitempty"` - // autoColor 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + // autoColor 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认false AutoColor bool `json:"auto_color,omitempty"` // lineColor AutoColor 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"},十进制表示 - LineColor Color `json:"line_color,omitempty"` - // isHyaline 是否需要透明底色 + LineColor *Color `json:"line_color,omitempty"` + // isHyaline 是否需要透明底色,默认false IsHyaline bool `json:"is_hyaline,omitempty"` // envVersion 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop" EnvVersion string `json:"env_version,omitempty"` From 8e81a416c5ccfc35beee46f79c5c9a493a804bcc Mon Sep 17 00:00:00 2001 From: houseme Date: Thu, 14 Apr 2022 10:07:58 +0800 Subject: [PATCH 38/84] Adaptation of new go-redis components (#546) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feature] Format the code and improve Mini Program authorization to obtain openid(miniprogram/auth/auth.go Code2Session) * [feature] CheckEncryptedData (https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/user-info/auth.checkEncryptedData.html) * upgrade json error * upgrade json error * [feature] Wallet Transfer returns the pointer object * feat:Adaptation of new go-redis components * improve code * feat:upgrade golangci-lint-action version * fix * test ci * fix * test ci * fix * test * improve code * feat:GetPhoneNumber return ptr Co-authored-by: houseme --- .github/ISSUE_TEMPLATE.md | 1 + .github/workflows/go.yml | 13 ++- README.md | 10 ++- cache/redis.go | 94 ++++++--------------- cache/redis_test.go | 29 ++++--- doc/api/README.md | 3 +- doc/api/aispeech.md | 1 + doc/api/minigame.md | 1 + doc/api/miniprogram.md | 1 + doc/api/wxpay.md | 1 + go.mod | 16 ++-- go.sum | 140 +++++++++++++++++++++++++------ minigame/README.md | 1 + miniprogram/README.md | 3 +- miniprogram/auth/auth.go | 2 +- miniprogram/tcb/README.md | 2 + officialaccount/server/server.go | 3 +- openplatform/README.md | 4 +- pay/notify/paid.go | 3 +- wechat.go | 3 +- work/kf/account.go | 4 +- work/kf/client.go | 2 +- work/kf/error.go | 4 +- work/kf/other.go | 2 +- work/kf/sendmsg.go | 2 +- work/kf/sendmsgonevent.go | 2 +- work/kf/servicer.go | 6 +- work/kf/syncmsg.go | 2 +- work/kf/upgrade.go | 4 +- work/msgaudit/error.go | 26 +++--- 30 files changed, 232 insertions(+), 153 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 5d6e38c..f34eaa6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,2 +1,3 @@ ## 问题及现象 +