123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- package wechat
- import (
- "encoding/json"
- "net/url"
- "time"
- )
- // Client wechat
- type Client struct {
- AppID string `json:"appid"`
- AppSecret string `json:"appsecret"`
- Token string `json:"token"`
- EncodingAESKey string `json:"encodingaeskey"`
- AccessToken string
- LastTokenTime int64
- }
- // FormAuthorize get code
- type FormAuthorize struct {
- Code string `form:"code"`
- State string `form:"state"`
- URL string `form:"url"`
- }
- // FormOpenID openid
- type FormOpenID struct {
- OpenID string `form:"openid"`
- }
- // FormMaterial Material
- type FormMaterial struct {
- Type string `form:"type"`
- Offset int `form:"offset"`
- Count int `form:"count"`
- }
- // UserInfo userinfo
- type UserInfo struct {
- SubScribe int `json:"subscribe"`
- OpenID string `json:"openid"`
- NickName string `json:"nickname"`
- Sex int `json:"sex"`
- Language string `json:"language"`
- City string `json:"city"`
- Province string `json:"province"`
- Country string `json:"country"`
- HeadImgURL string `json:"headimgurl"`
- SubscribeTime int `json:"subscribe_time"`
- Remark string `json:"remark"`
- GroupID int `json:"groupid"`
- TagidList []int `json:"tagid_list"`
- SubscribeScene string `json:"subscribe_scene"`
- QrScene int `json:"qr_scene"`
- QrSceneStr string `json:"qr_scene_str"`
- }
- // List openid list
- type List struct {
- OpenID []string `json:"openid"`
- }
- // UserList user list
- type UserList struct {
- Total int `json:"total"`
- Count int `json:"count"`
- Data List `json:"data"`
- NextOpenID string `json:"next_openid"`
- }
- type newsitem struct {
- Title string `json:"title"`
- Author string `json:"author"`
- Digest string `json:"digest"`
- Content string `json:"content"`
- ContentSourceURL string `json:"content_source_url"`
- ThumbMediaID string `json:"thumb_media_id"`
- ShowCoverPic int `json:"show_cover_pic"`
- URL string `json:"url"`
- ThumbURL string `json:"thumb_url"`
- NeedOpenComment int `json:"need_open_comment"`
- OnlyFansCanComment int `json:"only_fans_can_comment"`
- }
- type content struct {
- NewsItem []*newsitem `json:"news_item,omitempty"`
- CreateTime int `json:"create_time,omitempty"`
- UpdateTime int `json:"update_time,omitempty"`
- }
- type item struct {
- MediaID string `json:"media_id"`
- Name string `json:"name,omitempty"`
- UpdateTime int `json:"update_time"`
- URL string `json:"url,omitempty"`
- Content *content `json:"content,omitempty"`
- }
- // Material 素材
- type Material struct {
- TotalCount int `json:"total_count"`
- ItemCount int `json:"item_count"`
- Item []item `json:"item"`
- }
- // MiniProgramPage mini
- type MiniProgramPage struct {
- AppID string `json:"appid,omitempty"`
- PagePath string `json:"pagepath,omitempty"`
- }
- // ValueColor value color
- type ValueColor struct {
- Value string `json:"value"`
- Color string `json:"color,omitempty"`
- }
- // TemplateData data
- type TemplateData struct {
- First *ValueColor `json:"first"`
- Keyword1 *ValueColor `json:"keyword1,omitempty"`
- Keyword2 *ValueColor `json:"keyword2,omitempty"`
- Keyword3 *ValueColor `json:"keyword3,omitempty"`
- Keyword4 *ValueColor `json:"keyword4,omitempty"`
- Keyword5 *ValueColor `json:"keyword5,omitempty"`
- Remark *ValueColor `json:"remark,omitempty"`
- }
- // TemplateMessage template message
- type TemplateMessage struct {
- ToUser string `json:"touser"`
- TemplateID string `json:"template_id"`
- URL string `json:"url"`
- MiniProgram *MiniProgramPage `json:"miniprogram,omitempty"`
- Data TemplateData `json:"data"`
- }
- func key(appid string) string {
- return "wechat:client:" + appid
- }
- // NewClient new client
- func NewClient(appID, appSecret, token, encodingAESKey string) *Client {
- key := key(appID)
- if v, ok := cache.Load(key); ok {
- return v.(*Client)
- }
- c := &Client{AppID: appID, AppSecret: appSecret, Token: token, EncodingAESKey: encodingAESKey}
- cache.Store(key, c)
- return c
- }
- // getToken get token
- func (wc *Client) getToken() (token string, err error) {
- now := time.Now().Unix()
- if wc.LastTokenTime > 0 {
- if now-wc.LastTokenTime < TokenExpires {
- token = wc.AccessToken
- return
- }
- }
- uri := BaseURL + "/cgi-bin/token?"
- args := url.Values{}
- args.Add("grant_type", "client_credential")
- args.Add("appid", wc.AppID)
- args.Add("secret", wc.AppSecret)
- uri += args.Encode()
- var res Response
- if res, err = getJSON(uri); err == nil {
- wc.LastTokenTime = now
- wc.AccessToken = res.AccessToken
- token = wc.AccessToken
- key := key(wc.AppID)
- cache.Store(key, wc)
- }
- return
- }
- // GetCodeURL get code 授权获取 OpenID URL
- // /connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
- // 转向到
- // redirect_uri/?code=CODE&state=STATE
- func (wc Client) GetCodeURL(redirectURL, state string) (uri string) {
- uri = OpenURL + "/connect/oauth2/authorize?"
- args := url.Values{}
- args.Add("appid", wc.AppID)
- args.Add("redirect_uri", redirectURL)
- args.Add("response_type", "code")
- args.Add("scope", "snsapi_base")
- args.Add("state", state)
- uri += args.Encode()
- uri += "#wechat_redirect"
- return
- }
- // GetOpenID 获取 OpenID
- // /sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
- func (wc Client) GetOpenID(code string) (res Response, err error) {
- uri := BaseURL + "/sns/oauth2/access_token?"
- if wc.AccessToken, err = wc.getToken(); err != nil {
- return
- }
- args := url.Values{}
- args.Add("access_token", wc.AccessToken)
- args.Add("appid", wc.AppID)
- args.Add("secret", wc.AppSecret)
- args.Add("code", code)
- args.Add("grant_type", "authorization_code")
- uri += args.Encode()
- res, err = getJSON(uri)
- return
- }
- // GetUserInfo user info
- func (wc Client) GetUserInfo(openid string) (res UserInfo, err error) {
- uri := BaseURL + "/cgi-bin/user/info?"
- if wc.AccessToken, err = wc.getToken(); err != nil {
- return
- }
- args := url.Values{}
- args.Add("access_token", wc.AccessToken)
- args.Add("openid", openid)
- args.Add("lang", "zh_CN")
- uri += args.Encode()
- var body []byte
- body, err = getBody(uri)
- if err == nil {
- err = json.Unmarshal(body, &res)
- }
- return
- }
- // GetUserList user list
- func (wc Client) GetUserList(nextOpenID string) (res UserList, err error) {
- uri := BaseURL + "/cgi-bin/user/get?"
- if wc.AccessToken, err = wc.getToken(); err != nil {
- return
- }
- args := url.Values{}
- args.Add("access_token", wc.AccessToken)
- args.Add("next_openid", nextOpenID)
- uri += args.Encode()
- var body []byte
- body, err = getBody(uri)
- if err == nil {
- err = json.Unmarshal(body, &res)
- }
- return
- }
- // GetMaterial 永久资料
- func (wc Client) GetMaterial(mtype string, offset, count int) (res Material, err error) {
- uri := BaseURL + "/cgi-bin/material/batchget_material?"
- if wc.AccessToken, err = wc.getToken(); err != nil {
- return
- }
- args := url.Values{}
- data := make(map[string]interface{})
- args.Add("access_token", wc.AccessToken)
- data["type"] = mtype
- data["offset"] = offset
- data["count"] = count
- uri += args.Encode()
- var body []byte
- params, err := json.Marshal(data)
- body, err = postBody(uri, params)
- if err == nil {
- err = json.Unmarshal(body, &res)
- }
- return
- }
- // SendTemplateMessage send template message
- // POST /cgi-bin/message/template/send?access_token=ACCESS_TOKEN
- func (wc Client) SendTemplateMessage(template TemplateMessage) (res Response, err error) {
- uri := BaseURL + "/cgi-bin/message/template/send?"
- if wc.AccessToken, err = wc.getToken(); err != nil {
- return
- }
- args := url.Values{}
- args.Add("access_token", wc.AccessToken)
- uri += args.Encode()
- data, err := json.Marshal(template)
- if err != nil {
- return
- }
- res, err = postJSON(uri, data)
- return
- }
|