Procházet zdrojové kódy

公众号用户黑名单管理 (#609)

gzylg před 3 roky
rodič
revize
88fc6465bb
2 změnil soubory, kde provedl 190 přidání a 57 odebrání
  1. 74 57
      doc/api/officialaccount.md
  2. 116 0
      officialaccount/user/blacklist.go

+ 74 - 57
doc/api/officialaccount.md

@@ -1,29 +1,29 @@
-# 微信公众号API列表
+# 微信公众号 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        |          |
+|           名称            | 请求方式 | 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            | YES        | (tpl *Subscribe) GetCategory |
-| 获取模板中的关键词   | GET      | /wxaapi/newtmpl/getpubtemplatekeywords | YES        | (tpl *Subscribe) GetPubTplKeyWordsByID |
-| 获取类目下的公共模板 | GET      | /wxaapi/newtmpl/getpubtemplatetitles   | YES        | (tpl *Subscribe) GetPublicTemplateTitleList |
-| 获取私有模板列表     | GET      | /wxaapi/newtmpl/gettemplate            | YES        | (tpl *Subscribe) List() |
-| 发送订阅通知         | POST     | /cgi-bin/message/subscribe/bizsend     | YES        | (tpl *Subscribe) Send   |
+| 名称                 | 请求方式 | URL                                    | 是否已实现 | 使用方法                                     |
+| -------------------- | -------- | -------------------------------------- | ---------- | -------------------------------------------- |
+| 选用模板             | POST     | /wxaapi/newtmpl/addtemplate            | YES        | (tpl \*Subscribe) Add                        |
+| 删除模板             | POST     | /wxaapi/newtmpl/deltemplate            | YES        | (tpl \*Subscribe) Delete                     |
+| 获取公众号类目       | GET      | /wxaapi/newtmpl/getcategory            | YES        | (tpl \*Subscribe) GetCategory                |
+| 获取模板中的关键词   | GET      | /wxaapi/newtmpl/getpubtemplatekeywords | YES        | (tpl \*Subscribe) GetPubTplKeyWordsByID      |
+| 获取类目下的公共模板 | GET      | /wxaapi/newtmpl/getpubtemplatetitles   | YES        | (tpl \*Subscribe) GetPublicTemplateTitleList |
+| 获取私有模板列表     | GET      | /wxaapi/newtmpl/gettemplate            | YES        | (tpl \*Subscribe) List()                     |
+| 发送订阅通知         | POST     | /cgi-bin/message/subscribe/bizsend     | YES        | (tpl \*Subscribe) Send                       |
 
 ## 客服消息
 
@@ -33,16 +33,16 @@
 
 [官方文档](https://developers.weixin.qq.com/doc/offiaccount/Customer_Service/Customer_Service_Management.html)
 
-| 名称             | 请求方式  | URL                                    | 是否已实现 | 使用方法 |
-| ---------------- | --------- | -------------------------------------- | ---------- | -------- |
-| 获取客服基本信息 | GET       | /cgi-bin/customservice/getkflist       | YES       | (csm *Manager) List |
-| 添加客服帐号     | POST      | /customservice/kfaccount/add           | YES       | (csm *Manager) Add |
-| 邀请绑定客服帐号 | POST      | /customservice/kfaccount/inviteworker  | YES       | (csm *Manager) InviteBind |
-| 设置客服信息     | POST      | /customservice/kfaccount/update        | YES       | (csm *Manager) Update |
-| 上传客服头像     | POST/FORM | /customservice/kfaccount/uploadheadimg | YES       | (csm *Manager) UploadHeadImg |
-| 删除客服帐号     | POST      | /customservice/kfaccount/del           | YES       | (csm *Manager) Delete |
-| 获取在线客服     | POST      |  /cgi-bin/customservice/getonlinekflist| YES       | (csm *Manager) OnlineList |
-| 下发客服输入状态 | POST      |  /cgi-bin/message/custom/typing        | YES       | (csm *Manager) SendTypingStatus |
+| 名称             | 请求方式  | URL                                    | 是否已实现 | 使用方法                         |
+| ---------------- | --------- | -------------------------------------- | ---------- | -------------------------------- |
+| 获取客服基本信息 | GET       | /cgi-bin/customservice/getkflist       | YES        | (csm \*Manager) List             |
+| 添加客服帐号     | POST      | /customservice/kfaccount/add           | YES        | (csm \*Manager) Add              |
+| 邀请绑定客服帐号 | POST      | /customservice/kfaccount/inviteworker  | YES        | (csm \*Manager) InviteBind       |
+| 设置客服信息     | POST      | /customservice/kfaccount/update        | YES        | (csm \*Manager) Update           |
+| 上传客服头像     | POST/FORM | /customservice/kfaccount/uploadheadimg | YES        | (csm \*Manager) UploadHeadImg    |
+| 删除客服帐号     | POST      | /customservice/kfaccount/del           | YES        | (csm \*Manager) Delete           |
+| 获取在线客服     | POST      | /cgi-bin/customservice/getonlinekflist | YES        | (csm \*Manager) OnlineList       |
+| 下发客服输入状态 | POST      | /cgi-bin/message/custom/typing         | YES        | (csm \*Manager) SendTypingStatus |
 
 #### 会话控制
 
@@ -148,15 +148,15 @@
 
 [官方文档](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                  |
+| 名称                                                                    | 请求方式 | 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                  |
 
 ## 素材管理
 
@@ -164,17 +164,15 @@
 
 [官方文档](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<br />/cgi-bin/draft/switch?checkonly=1 | NO         |                              |
-
-
+| 名称                        | 请求方式 | 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<br />/cgi-bin/draft/switch?checkonly=1 | NO         |                               |
 
 ## 发布能力
 
@@ -187,20 +185,40 @@
 - 群发:主动推送给粉丝,历史消息可看,被搜一搜收录,可以限定部分的粉丝接收到。
 - 发布:不会主动推给粉丝,历史消息列表看不到,但是是公开给所有人的文章。也不会占用群发的次数。每天可以发布多篇内容。可以用于自动回复、自定义菜单、页面模板和话题中,发布成功时会生成一个永久链接。
 
-| 名称                           | 请求方式 | 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     |
-
+| 名称                           | 请求方式 | 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     |
 
 ## 图文消息留言管理
 
 ## 用户管理
 
+| 名称                                       | 请求方式 | URL                                    | 是否已实现 | 使用方法                           |
+| ------------------------------------------ | -------- | -------------------------------------- | ---------- | ---------------------------------- |
+| 获取指定 OpenID 变化列表(公众号账号迁移) | POST     | /cgi-bin/changeopenid                  | YES        | (user \*User) ListChangeOpenIDs    |
+| 获取所有用户 OpenID 列表(公众号账号迁移) |          |                                        | YES        | (user \*User) ListAllChangeOpenIDs |
+| 获取用户基本信息                           | GET      | /cgi-bin/user/info                     | YES        | (user \*User) GetUserInfo          |
+| 设置用户备注名                             | POST     | /cgi-bin/user/info/updateremark        | YES        | (user \*User) UpdateRemark         |
+| 获取用户列表                               | GET      | /cgi-bin/user/get                      | YES        | (user \*User) ListUserOpenIDs      |
+| 获取所有用户 OpenID 列表                   |          |                                        | YES        | (user \*User) ListAllUserOpenIDs   |
+| 获取公众号的黑名单列表                     | POST     | /cgi-bin/tags/members/getblacklist     | YES        | (user \*User) GetBlackList         |
+| 获取公众号的所有黑名单列表                 |          |                                        | YES        | (user \*User) GetAllBlackList      |
+| 拉黑用户                                   | POST     | /cgi-bin/tags/members/batchblacklist   | YES        | (user \*User) BatchBlackList       |
+| 取消拉黑用户                               | POST     | /cgi-bin/tags/members/batchunblacklist | YES        | (user \*User) BatchUnBlackList     |
+| 创建标签                                   | POST     | /cgi-bin/tags/create                   | YES        | (user \*User) CreateTag            |
+| 删除标签                                   | POST     | /cgi-bin/tags/delete                   | YES        | (user \*User) DeleteTag            |
+| 编辑标签                                   | POST     | /cgi-bin/tags/update                   | YES        | (user \*User) UpdateTag            |
+| 获取公众号已创建的标签                     | GET      | /cgi-bin/tags/get                      | YES        | (user \*User) GetTag               |
+| 获取标签下粉丝列表                         | POST     | /cgi-bin/user/tag/get                  | YES        | (user \*User) OpenIDListByTag      |
+| 批量为用户打标签                           | POST     | /cgi-bin/tags/members/batchtagging     | YES        | (user \*User) BatchTag             |
+| 批量为用户取消标签                         | POST     | /cgi-bin/tags/members/batchuntagging   | YES        | (user \*User) BatchUntag           |
+| 获取用户身上的标签列表                     | POST     | /cgi-bin/tags/getidlist                | YES        | (user \*User) UserTidList          |
+
 ## 账号管理
 
 ## 数据统计
@@ -217,5 +235,4 @@
 
 ## 微信发票
 
-## 微信非税缴费 
-
+## 微信非税缴费

+ 116 - 0
officialaccount/user/blacklist.go

@@ -0,0 +1,116 @@
+// Package user blacklist 公众号用户黑名单管理
+// 参考文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/Manage_blacklist.html
+package user
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/silenceper/wechat/v2/util"
+)
+
+const (
+	// 获取公众号的黑名单列表
+	getblacklistURL = "https://api.weixin.qq.com/cgi-bin/tags/members/getblacklist?access_token=%s"
+	// 拉黑用户
+	batchblacklistURL = "https://api.weixin.qq.com/cgi-bin/tags/members/batchblacklist?access_token=%s"
+	// 取消拉黑用户
+	batchunblacklistURL = "https://api.weixin.qq.com/cgi-bin/tags/members/batchunblacklist?access_token=%s"
+)
+
+// GetBlackList 获取公众号的黑名单列表
+// 该接口每次调用最多可拉取 1000 个OpenID,当列表数较多时,可以通过多次拉取的方式来满足需求。
+// 参数 beginOpenid:当 begin_openid 为空时,默认从开头拉取。
+func (user *User) GetBlackList(beginOpenid ...string) (userlist *OpenidList, err error) {
+	if len(beginOpenid) > 1 {
+		return nil, errors.New("参数 beginOpenid 错误:请传递 1 个openID,若需要从头开始拉取列表请留空。")
+	}
+	// 获取 AccessToken
+	var accessToken string
+	if accessToken, err = user.GetAccessToken(); err != nil {
+		return
+	}
+
+	// 处理 request 内容
+	request := map[string]string{"begin_openid": ""}
+	if len(beginOpenid) == 1 {
+		request["begin_openid"] = beginOpenid[0]
+	}
+
+	// 调用接口
+	var resp []byte
+	url := fmt.Sprintf(getblacklistURL, accessToken)
+	if resp, err = util.PostJSON(url, &request); err != nil {
+		return nil, err
+	}
+
+	// 处理返回
+	userlist = &OpenidList{}
+	if err = util.DecodeWithError(resp, userlist, "GetBlackList"); err != nil {
+		return nil, err
+	}
+
+	return
+}
+
+// GetAllBlackList 获取公众号的所有黑名单列表
+func (user *User) GetAllBlackList() (openIDList []string, err error) {
+	var (
+		beginOpenid string
+		count       int
+		userlist    *OpenidList
+	)
+
+	for {
+		// 获取列表(每次1k条)
+		if userlist, err = user.GetBlackList(beginOpenid); err != nil {
+			return nil, err
+		}
+		openIDList = append(openIDList, userlist.Data.OpenIDs...) // 存储本次获得的OpenIDs
+		count += userlist.Count                                   // 记录获得的总数量
+		beginOpenid = userlist.NextOpenID                         // 记录下次循环的起始openID
+		if count >= userlist.Total {
+			break // 获得的数量=total,结束循环
+		}
+	}
+
+	return
+}
+
+// BatchBlackList 拉黑用户
+// 参数 openidList:需要拉入黑名单的用户的openid,每次拉黑最多允许20个
+func (user *User) BatchBlackList(openidList ...string) (err error) {
+	return user.batch(batchblacklistURL, "BatchBlackList", openidList...)
+}
+
+// BatchUnBlackList 取消拉黑用户
+// 参数 openidList:需要取消拉入黑名单的用户的openid,每次拉黑最多允许20个
+func (user *User) BatchUnBlackList(openidList ...string) (err error) {
+	return user.batch(batchunblacklistURL, "BatchUnBlackList", openidList...)
+}
+
+// batch 公共方法
+func (user *User) batch(url, apiName string, openidList ...string) (err error) {
+	// 检查参数
+	if len(openidList) == 0 || len(openidList) > 20 {
+		return errors.New("参数 openidList 错误:每次操作黑名单用户数量为1-20个。")
+	}
+
+	// 获取 AccessToken
+	var accessToken string
+	if accessToken, err = user.GetAccessToken(); err != nil {
+		return
+	}
+
+	// 处理 request 内容
+	request := map[string][]string{"openid_list": openidList}
+
+	// 调用接口
+	var resp []byte
+	url = fmt.Sprintf(url, accessToken)
+	if resp, err = util.PostJSON(url, &request); err != nil {
+		return
+	}
+
+	return util.DecodeWithCommonError(resp, apiName)
+}