From 88fc6465bb8a06dc5b4659ce3a19895f7b49740d Mon Sep 17 00:00:00 2001 From: gzylg <40072122+gzylg@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:50:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=AC=E4=BC=97=E5=8F=B7=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E9=BB=91=E5=90=8D=E5=8D=95=E7=AE=A1=E7=90=86=20(#609)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/api/officialaccount.md | 131 +++++++++++++++++------------- officialaccount/user/blacklist.go | 116 ++++++++++++++++++++++++++ 2 files changed, 190 insertions(+), 57 deletions(-) create mode 100644 officialaccount/user/blacklist.go diff --git a/doc/api/officialaccount.md b/doc/api/officialaccount.md index 46d0bb6..5b81b4e 100644 --- a/doc/api/officialaccount.md +++ b/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
/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
/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 @@ ## 微信发票 -## 微信非税缴费 - +## 微信非税缴费 diff --git a/officialaccount/user/blacklist.go b/officialaccount/user/blacklist.go new file mode 100644 index 0000000..b957b09 --- /dev/null +++ b/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) +}