mirror of
https://github.com/silenceper/wechat.git
synced 2026-03-01 00:35:26 +08:00
Compare commits
8 Commits
9d8b803b33
...
v2.1.5-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cb741ae1a | ||
|
|
da3859261b | ||
|
|
86ceb6af2f | ||
|
|
243f8198ae | ||
|
|
2bc0536c02 | ||
|
|
bbbada1b44 | ||
|
|
5380d5bee7 | ||
|
|
a03f3f9f32 |
@@ -1,6 +1,14 @@
|
|||||||
package credential
|
package credential
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
// AccessTokenHandle AccessToken 接口
|
// AccessTokenHandle AccessToken 接口
|
||||||
type AccessTokenHandle interface {
|
type AccessTokenHandle interface {
|
||||||
GetAccessToken() (accessToken string, err error)
|
GetAccessToken() (accessToken string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AccessTokenContextHandle AccessToken 接口
|
||||||
|
type AccessTokenContextHandle interface {
|
||||||
|
AccessTokenHandle
|
||||||
|
GetAccessTokenContext(ctx context.Context) (accessToken string, err error)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package credential
|
package credential
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -33,7 +34,7 @@ type DefaultAccessToken struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewDefaultAccessToken new DefaultAccessToken
|
// NewDefaultAccessToken new DefaultAccessToken
|
||||||
func NewDefaultAccessToken(appID, appSecret, cacheKeyPrefix string, cache cache.Cache) AccessTokenHandle {
|
func NewDefaultAccessToken(appID, appSecret, cacheKeyPrefix string, cache cache.Cache) AccessTokenContextHandle {
|
||||||
if cache == nil {
|
if cache == nil {
|
||||||
panic("cache is ineed")
|
panic("cache is ineed")
|
||||||
}
|
}
|
||||||
@@ -56,6 +57,11 @@ type ResAccessToken struct {
|
|||||||
|
|
||||||
// GetAccessToken 获取access_token,先从cache中获取,没有则从服务端获取
|
// GetAccessToken 获取access_token,先从cache中获取,没有则从服务端获取
|
||||||
func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) {
|
func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) {
|
||||||
|
return ak.GetAccessTokenContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccessTokenContext 获取access_token,先从cache中获取,没有则从服务端获取
|
||||||
|
func (ak *DefaultAccessToken) GetAccessTokenContext(ctx context.Context) (accessToken string, err error) {
|
||||||
// 先从cache中取
|
// 先从cache中取
|
||||||
accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", ak.cacheKeyPrefix, ak.appID)
|
accessTokenCacheKey := fmt.Sprintf("%s_access_token_%s", ak.cacheKeyPrefix, ak.appID)
|
||||||
if val := ak.cache.Get(accessTokenCacheKey); val != nil {
|
if val := ak.cache.Get(accessTokenCacheKey); val != nil {
|
||||||
@@ -73,7 +79,7 @@ func (ak *DefaultAccessToken) GetAccessToken() (accessToken string, err error) {
|
|||||||
|
|
||||||
// cache失效,从微信服务器获取
|
// cache失效,从微信服务器获取
|
||||||
var resAccessToken ResAccessToken
|
var resAccessToken ResAccessToken
|
||||||
resAccessToken, err = GetTokenFromServer(fmt.Sprintf(accessTokenURL, ak.appID, ak.appSecret))
|
resAccessToken, err = GetTokenFromServerContext(ctx, fmt.Sprintf(accessTokenURL, ak.appID, ak.appSecret))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -97,7 +103,7 @@ type WorkAccessToken struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewWorkAccessToken new WorkAccessToken
|
// NewWorkAccessToken new WorkAccessToken
|
||||||
func NewWorkAccessToken(corpID, corpSecret, cacheKeyPrefix string, cache cache.Cache) AccessTokenHandle {
|
func NewWorkAccessToken(corpID, corpSecret, cacheKeyPrefix string, cache cache.Cache) AccessTokenContextHandle {
|
||||||
if cache == nil {
|
if cache == nil {
|
||||||
panic("cache the not exist")
|
panic("cache the not exist")
|
||||||
}
|
}
|
||||||
@@ -112,6 +118,11 @@ 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) {
|
func (ak *WorkAccessToken) GetAccessToken() (accessToken string, err error) {
|
||||||
|
return ak.GetAccessTokenContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccessTokenContext 企业微信获取access_token,先从cache中获取,没有则从服务端获取
|
||||||
|
func (ak *WorkAccessToken) GetAccessTokenContext(ctx context.Context) (accessToken string, err error) {
|
||||||
// 加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token
|
// 加上lock,是为了防止在并发获取token时,cache刚好失效,导致从微信服务器上获取到不同token
|
||||||
ak.accessTokenLock.Lock()
|
ak.accessTokenLock.Lock()
|
||||||
defer ak.accessTokenLock.Unlock()
|
defer ak.accessTokenLock.Unlock()
|
||||||
@@ -124,7 +135,7 @@ func (ak *WorkAccessToken) GetAccessToken() (accessToken string, err error) {
|
|||||||
|
|
||||||
// cache失效,从微信服务器获取
|
// cache失效,从微信服务器获取
|
||||||
var resAccessToken ResAccessToken
|
var resAccessToken ResAccessToken
|
||||||
resAccessToken, err = GetTokenFromServer(fmt.Sprintf(workAccessTokenURL, ak.CorpID, ak.CorpSecret))
|
resAccessToken, err = GetTokenFromServerContext(ctx, fmt.Sprintf(workAccessTokenURL, ak.CorpID, ak.CorpSecret))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -140,8 +151,13 @@ func (ak *WorkAccessToken) GetAccessToken() (accessToken string, err error) {
|
|||||||
|
|
||||||
// GetTokenFromServer 强制从微信服务器获取token
|
// GetTokenFromServer 强制从微信服务器获取token
|
||||||
func GetTokenFromServer(url string) (resAccessToken ResAccessToken, err error) {
|
func GetTokenFromServer(url string) (resAccessToken ResAccessToken, err error) {
|
||||||
|
return GetTokenFromServerContext(context.Background(), url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTokenFromServerContext 强制从微信服务器获取token
|
||||||
|
func GetTokenFromServerContext(ctx context.Context, url string) (resAccessToken ResAccessToken, err error) {
|
||||||
var body []byte
|
var body []byte
|
||||||
body, err = util.HTTPGet(url)
|
body, err = util.HTTPGetContext(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,16 +62,25 @@ host: https://qyapi.weixin.qq.com/
|
|||||||
### 客户联系
|
### 客户联系
|
||||||
[官方文档](https://developer.work.weixin.qq.com/document/path/92132/92133/92228)
|
[官方文档](https://developer.work.weixin.qq.com/document/path/92132/92133/92228)
|
||||||
|
|
||||||
| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | 贡献者 |
|
| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | 贡献者 |
|
||||||
|:---------------:| -------- | :---------------------------------------| ---------- | ------------------------------- |----------|
|
|:------------------------:| -------- |:-------------------------------------------------------------| ---------- | ------------------------------- |----------|
|
||||||
| 获取「联系客户统计」数据 | POST | /cgi-bin/externalcontact/get_user_behavior_data | YES | (r *Client) GetUserBehaviorData | MARKWANG |
|
| 获取「联系客户统计」数据 | POST | /cgi-bin/externalcontact/get_user_behavior_data | YES | (r *Client) GetUserBehaviorData | MARKWANG |
|
||||||
| 获取「群聊数据统计」数据 (按群主聚合的方式) | POST | /cgi-bin/externalcontact/groupchat/statistic | YES | (r *Client) GetGroupChatStat | MARKWANG |
|
| 获取「群聊数据统计」数据 (按群主聚合的方式) | POST | /cgi-bin/externalcontact/groupchat/statistic | YES | (r *Client) GetGroupChatStat | MARKWANG |
|
||||||
| 获取「群聊数据统计」数据 (按自然日聚合的方式) | POST | /cgi-bin/externalcontact/groupchat/statistic_group_by_day | YES | (r *Client) GetGroupChatStatByDay | MARKWANG |
|
| 获取「群聊数据统计」数据 (按自然日聚合的方式) | POST | /cgi-bin/externalcontact/groupchat/statistic_group_by_day | YES | (r *Client) GetGroupChatStatByDay | MARKWANG |
|
||||||
| 配置客户联系「联系我」方式 | POST | /cgi-bin/externalcontact/add_contact_way | YES | (r *Client) AddContactWay | MARKWANG |
|
| 配置客户联系「联系我」方式 | POST | /cgi-bin/externalcontact/add_contact_way | YES | (r *Client) AddContactWay | MARKWANG |
|
||||||
| 获取企业已配置的「联系我」方式 | POST | /cgi-bin/externalcontact/get_contact_way | YES | (r *Client) GetContactWay | MARKWANG |
|
| 获取企业已配置的「联系我」方式 | POST | /cgi-bin/externalcontact/get_contact_way | YES | (r *Client) GetContactWay | MARKWANG |
|
||||||
| 更新企业已配置的「联系我」方式 | POST | /cgi-bin/externalcontact/update_contact_way | YES | (r *Client) UpdateContactWay | MARKWANG |
|
| 更新企业已配置的「联系我」方式 | POST | /cgi-bin/externalcontact/update_contact_way | YES | (r *Client) UpdateContactWay | MARKWANG |
|
||||||
| 获取企业已配置的「联系我」列表 | POST | /cgi-bin/externalcontact/list_contact_way | YES | (r *Client) ListContactWay | MARKWANG |
|
| 获取企业已配置的「联系我」列表 | POST | /cgi-bin/externalcontact/list_contact_way | YES | (r *Client) ListContactWay | MARKWANG |
|
||||||
| 删除企业已配置的「联系我」方式 | POST | /cgi-bin/externalcontact/del_contact_way | YES | (r *Client) DelContactWay | MARKWANG |
|
| 删除企业已配置的「联系我」方式 | POST | /cgi-bin/externalcontact/del_contact_way | YES | (r *Client) DelContactWay | MARKWANG |
|
||||||
|
| 创建企业群发 | POST | /cgi-bin/externalcontact/add_msg_template | YES | (r *Client) AddMsgTemplate | MARKWANG |
|
||||||
|
| 获取群发记录列表 | POST | /cgi-bin/externalcontact/get_groupmsg_list_v2 | YES | (r *Client) GetGroupMsgListV2 | MARKWANG |
|
||||||
|
| 获取群发成员发送任务列表 | POST | /cgi-bin/externalcontact/get_groupmsg_task | YES | (r *Client) GetGroupMsgTask | MARKWANG |
|
||||||
|
| 获取企业群发成员执行结果 | POST | /cgi-bin/externalcontact/get_groupmsg_send_result | YES | (r *Client) GetGroupMsgSendResult | MARKWANG |
|
||||||
|
| 发送新客户欢迎语 | POST | /cgi-bin/externalcontact/send_welcome_msg | YES | (r *Client) SendWelcomeMsg | MARKWANG |
|
||||||
|
| 添加入群欢迎语素材 | POST | /cgi-bin/externalcontact/group_welcome_template/add | YES | (r *Client) AddGroupWelcomeTemplate | MARKWANG |
|
||||||
|
| 编辑入群欢迎语素材 | POST | /cgi-bin/externalcontact/group_welcome_template/edit | YES | (r *Client) EditGroupWelcomeTemplate | MARKWANG |
|
||||||
|
| 获取入群欢迎语素材 | POST | /cgi-bin/externalcontact/group_welcome_template/get | YES | (r *Client) GetGroupWelcomeTemplate | MARKWANG |
|
||||||
|
| 删除入群欢迎语素材 | POST | /cgi-bin/externalcontact/group_welcome_template/del | YES | (r *Client) DelGroupWelcomeTemplate | MARKWANG |
|
||||||
|
|
||||||
## 通讯录管理
|
## 通讯录管理
|
||||||
[官方文档](https://developer.work.weixin.qq.com/document/path/90193)
|
[官方文档](https://developer.work.weixin.qq.com/document/path/90193)
|
||||||
@@ -82,7 +91,15 @@ host: https://qyapi.weixin.qq.com/
|
|||||||
|:---------:|------|:----------------------------------------| ---------- | ------------------------------- |----------|
|
|:---------:|------|:----------------------------------------| ---------- | ------------------------------- |----------|
|
||||||
| 获取子部门ID列表 | GET | /cgi-bin/department/simplelist | YES | (r *Client) DepartmentSimpleList| MARKWANG |
|
| 获取子部门ID列表 | GET | /cgi-bin/department/simplelist | YES | (r *Client) DepartmentSimpleList| MARKWANG |
|
||||||
| 获取部门成员 | GET | /cgi-bin/user/simplelist | YES | (r *Client) UserSimpleList | MARKWANG |
|
| 获取部门成员 | GET | /cgi-bin/user/simplelist | YES | (r *Client) UserSimpleList | MARKWANG |
|
||||||
=======
|
| 获取成员ID列表 | Post | /cgi-bin/user/list_id | YES | (r *Client) UserListId | MARKWANG |
|
||||||
|
|
||||||
|
|
||||||
|
## 素材管理
|
||||||
|
[官方文档](https://developer.work.weixin.qq.com/document/path/91054)
|
||||||
|
|
||||||
|
| 名称 | 请求方式 | URL | 是否已实现 | 使用方法 | 贡献者 |
|
||||||
|
|:---------:|------|:----------------------------------------| ---------- | ------------------------------- |----------|
|
||||||
|
| 上传图片 | POST | /cgi-bin/media/uploadimg | YES | (r *Client) UploadImg| MARKWANG |
|
||||||
|
|
||||||
### 成员管理
|
### 成员管理
|
||||||
|
|
||||||
@@ -91,7 +108,6 @@ host: https://qyapi.weixin.qq.com/
|
|||||||
| 读取成员 | GET | /cgi-bin/user/get | YES | (r *Client) UserGet | chcthink |
|
| 读取成员 | GET | /cgi-bin/user/get | YES | (r *Client) UserGet | chcthink |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 群机器人
|
## 群机器人
|
||||||
|
|
||||||
[官方文档](https://developer.work.weixin.qq.com/document/path/91770)
|
[官方文档](https://developer.work.weixin.qq.com/document/path/91770)
|
||||||
@@ -101,5 +117,4 @@ host: https://qyapi.weixin.qq.com/
|
|||||||
| 群机器人发送消息 | POST | /cgi-bin/webhook/send | YES | (r *Client) RobotBroadcast | chcthink |
|
| 群机器人发送消息 | POST | /cgi-bin/webhook/send | YES | (r *Client) RobotBroadcast | chcthink |
|
||||||
|
|
||||||
## 应用管理
|
## 应用管理
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|||||||
5
go.sum
5
go.sum
@@ -26,12 +26,10 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
|||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||||
@@ -48,7 +46,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
|
|||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
|
|
||||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
@@ -118,7 +115,6 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
@@ -127,7 +123,6 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
|
|||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -80,6 +80,12 @@ const (
|
|||||||
EventSubscribeMsgPopupEvent EventType = "subscribe_msg_popup_event"
|
EventSubscribeMsgPopupEvent EventType = "subscribe_msg_popup_event"
|
||||||
// EventPublishJobFinish 发布任务完成
|
// EventPublishJobFinish 发布任务完成
|
||||||
EventPublishJobFinish EventType = "PUBLISHJOBFINISH"
|
EventPublishJobFinish EventType = "PUBLISHJOBFINISH"
|
||||||
|
// EventWeappAuditSuccess 审核通过
|
||||||
|
EventWeappAuditSuccess EventType = "weapp_audit_success"
|
||||||
|
// EventWeappAuditFail 审核不通过
|
||||||
|
EventWeappAuditFail EventType = "weapp_audit_fail"
|
||||||
|
// EventWeappAuditDelay 审核延后
|
||||||
|
EventWeappAuditDelay EventType = "weapp_audit_delay"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -209,6 +215,13 @@ type MixMessage struct {
|
|||||||
|
|
||||||
// 设备相关
|
// 设备相关
|
||||||
device.MsgDevice
|
device.MsgDevice
|
||||||
|
|
||||||
|
//小程序审核通知
|
||||||
|
SuccTime int `xml:"SuccTime"` //审核成功时的时间戳
|
||||||
|
FailTime int `xml:"FailTime"` //审核不通过的时间戳
|
||||||
|
DelayTime int `xml:"DelayTime"` //审核延后时的时间戳
|
||||||
|
Reason string `xml:"Reason"` //审核不通过的原因
|
||||||
|
ScreenShot string `xml:"ScreenShot"` //审核不通过的截图示例。用 | 分隔的 media_id 的列表,可通过获取永久素材接口拉取截图内容
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeMsgPopupEvent 订阅通知事件推送的消息体
|
// SubscribeMsgPopupEvent 订阅通知事件推送的消息体
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package officialaccount
|
package officialaccount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
stdcontext "context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/silenceper/wechat/v2/officialaccount/draft"
|
"github.com/silenceper/wechat/v2/officialaccount/draft"
|
||||||
@@ -94,6 +95,14 @@ func (officialAccount *OfficialAccount) GetAccessToken() (string, error) {
|
|||||||
return officialAccount.ctx.GetAccessToken()
|
return officialAccount.ctx.GetAccessToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAccessTokenContext 获取access_token
|
||||||
|
func (officialAccount *OfficialAccount) GetAccessTokenContext(ctx stdcontext.Context) (string, error) {
|
||||||
|
if c, ok := officialAccount.ctx.AccessTokenHandle.(credential.AccessTokenContextHandle); ok {
|
||||||
|
return c.GetAccessTokenContext(ctx)
|
||||||
|
}
|
||||||
|
return officialAccount.ctx.GetAccessToken()
|
||||||
|
}
|
||||||
|
|
||||||
// GetOauth oauth2网页授权
|
// GetOauth oauth2网页授权
|
||||||
func (officialAccount *OfficialAccount) GetOauth() *oauth.Oauth {
|
func (officialAccount *OfficialAccount) GetOauth() *oauth.Oauth {
|
||||||
if officialAccount.oauth == nil {
|
if officialAccount.oauth == nil {
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package miniprogram
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/v2/credential"
|
||||||
|
"github.com/silenceper/wechat/v2/miniprogram"
|
||||||
|
miniConfig "github.com/silenceper/wechat/v2/miniprogram/config"
|
||||||
miniContext "github.com/silenceper/wechat/v2/miniprogram/context"
|
miniContext "github.com/silenceper/wechat/v2/miniprogram/context"
|
||||||
"github.com/silenceper/wechat/v2/miniprogram/urllink"
|
"github.com/silenceper/wechat/v2/miniprogram/urllink"
|
||||||
openContext "github.com/silenceper/wechat/v2/openplatform/context"
|
openContext "github.com/silenceper/wechat/v2/openplatform/context"
|
||||||
@@ -14,7 +17,7 @@ import (
|
|||||||
type MiniProgram struct {
|
type MiniProgram struct {
|
||||||
AppID string
|
AppID string
|
||||||
openContext *openContext.Context
|
openContext *openContext.Context
|
||||||
|
*miniprogram.MiniProgram
|
||||||
authorizerRefreshToken string
|
authorizerRefreshToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,10 +45,13 @@ func (miniProgram *MiniProgram) SetAuthorizerRefreshToken(authorizerRefreshToken
|
|||||||
|
|
||||||
// NewMiniProgram 实例化
|
// NewMiniProgram 实例化
|
||||||
func NewMiniProgram(opCtx *openContext.Context, appID string) *MiniProgram {
|
func NewMiniProgram(opCtx *openContext.Context, appID string) *MiniProgram {
|
||||||
return &MiniProgram{
|
miniProgram := miniprogram.NewMiniProgram(&miniConfig.Config{
|
||||||
openContext: opCtx,
|
AppID: opCtx.AppID,
|
||||||
AppID: appID,
|
Cache: opCtx.Cache,
|
||||||
}
|
})
|
||||||
|
// 设置获取access_token的函数
|
||||||
|
miniProgram.SetAccessTokenHandle(NewDefaultAuthrAccessToken(opCtx, appID))
|
||||||
|
return &MiniProgram{AppID: appID, MiniProgram: miniProgram, openContext: opCtx}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetComponent get component
|
// GetComponent get component
|
||||||
@@ -65,3 +71,22 @@ func (miniProgram *MiniProgram) GetURLLink() *urllink.URLLink {
|
|||||||
AccessTokenHandle: miniProgram,
|
AccessTokenHandle: miniProgram,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultAuthrAccessToken 默认获取授权ak的方法
|
||||||
|
type DefaultAuthrAccessToken struct {
|
||||||
|
opCtx *openContext.Context
|
||||||
|
appID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultAuthrAccessToken 设置access_token
|
||||||
|
func NewDefaultAuthrAccessToken(opCtx *openContext.Context, appID string) credential.AccessTokenHandle {
|
||||||
|
return &DefaultAuthrAccessToken{
|
||||||
|
opCtx: opCtx,
|
||||||
|
appID: appID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccessToken 获取ak
|
||||||
|
func (ak *DefaultAuthrAccessToken) GetAccessToken() (string, error) {
|
||||||
|
return ak.opCtx.GetAuthrAccessToken(ak.appID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ const (
|
|||||||
UserSimpleListURL = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token=%s&department_id=%d"
|
UserSimpleListURL = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token=%s&department_id=%d"
|
||||||
// UserGetURL 读取成员
|
// UserGetURL 读取成员
|
||||||
UserGetURL = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=%s&userid=%s"
|
UserGetURL = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=%s&userid=%s"
|
||||||
|
// UserListIDURL 获取成员ID列表
|
||||||
|
UserListIDURL = "https://qyapi.weixin.qq.com/cgi-bin/user/list_id?access_token=%s"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -133,3 +135,43 @@ func (r *Client) UserGet(UserID string) (*UserGetResponse, error) {
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserListIDRequest 获取成员ID列表请求
|
||||||
|
type UserListIDRequest struct {
|
||||||
|
Cursor string `json:"cursor"`
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserListIDResponse 获取成员ID列表响应
|
||||||
|
type UserListIDResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
NextCursor string `json:"next_cursor"`
|
||||||
|
DeptUser []*DeptUser `json:"dept_user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeptUser 用户-部门关系
|
||||||
|
type DeptUser struct {
|
||||||
|
UserID string `json:"userid"`
|
||||||
|
Department int `json:"department"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserListID 获取成员ID列表
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/96067
|
||||||
|
func (r *Client) UserListID(req *UserListIDRequest) (*UserListIDResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(UserListIDURL, accessToken), req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &UserListIDResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "UserListID"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,23 +47,23 @@ func (r *Client) GetExternalUserList(userID string) ([]string, error) {
|
|||||||
// ExternalUserDetailResponse 外部联系人详情响应
|
// ExternalUserDetailResponse 外部联系人详情响应
|
||||||
type ExternalUserDetailResponse struct {
|
type ExternalUserDetailResponse struct {
|
||||||
util.CommonError
|
util.CommonError
|
||||||
ExternalUser
|
ExternalContact ExternalUser `json:"external_contact"`
|
||||||
|
FollowUser []FollowUser `json:"follow_user"`
|
||||||
|
NextCursor string `json:"next_cursor"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExternalUser 外部联系人
|
// ExternalUser 外部联系人
|
||||||
type ExternalUser struct {
|
type ExternalUser struct {
|
||||||
ExternalUserID string `json:"external_userid"`
|
ExternalUserID string `json:"external_userid"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
Type int64 `json:"type"`
|
Type int64 `json:"type"`
|
||||||
Gender int64 `json:"gender"`
|
Gender int64 `json:"gender"`
|
||||||
UnionID string `json:"unionid"`
|
UnionID string `json:"unionid"`
|
||||||
Position string `json:"position"`
|
Position string `json:"position"`
|
||||||
CorpName string `json:"corp_name"`
|
CorpName string `json:"corp_name"`
|
||||||
CorpFullName string `json:"corp_full_name"`
|
CorpFullName string `json:"corp_full_name"`
|
||||||
ExternalProfile string `json:"external_profile"`
|
ExternalProfile string `json:"external_profile"`
|
||||||
FollowUser []FollowUser `json:"follow_user"`
|
|
||||||
NextCursor string `json:"next_cursor"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FollowUser 跟进用户(指企业内部用户)
|
// FollowUser 跟进用户(指企业内部用户)
|
||||||
@@ -96,7 +96,8 @@ type WechatChannel struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetExternalUserDetail 获取外部联系人详情
|
// GetExternalUserDetail 获取外部联系人详情
|
||||||
func (r *Client) GetExternalUserDetail(externalUserID string, nextCursor ...string) (*ExternalUser, error) {
|
// @see https://developer.work.weixin.qq.com/document/path/92114
|
||||||
|
func (r *Client) GetExternalUserDetail(externalUserID string, nextCursor ...string) (*ExternalUserDetailResponse, error) {
|
||||||
accessToken, err := r.GetAccessToken()
|
accessToken, err := r.GetAccessToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -106,12 +107,12 @@ func (r *Client) GetExternalUserDetail(externalUserID string, nextCursor ...stri
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var result ExternalUserDetailResponse
|
result := &ExternalUserDetailResponse{}
|
||||||
err = util.DecodeWithError(response, &result, "get_external_user_detail")
|
err = util.DecodeWithError(response, result, "get_external_user_detail")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result.ExternalUser, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchGetExternalUserDetailsRequest 批量获取外部联系人详情请求
|
// BatchGetExternalUserDetailsRequest 批量获取外部联系人详情请求
|
||||||
@@ -161,6 +162,7 @@ type FollowInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BatchGetExternalUserDetails 批量获取外部联系人详情
|
// BatchGetExternalUserDetails 批量获取外部联系人详情
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/92994
|
||||||
func (r *Client) BatchGetExternalUserDetails(request BatchGetExternalUserDetailsRequest) ([]ExternalUserForBatch, error) {
|
func (r *Client) BatchGetExternalUserDetails(request BatchGetExternalUserDetailsRequest) ([]ExternalUserForBatch, error) {
|
||||||
accessToken, err := r.GetAccessToken()
|
accessToken, err := r.GetAccessToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -195,6 +197,7 @@ type UpdateUserRemarkRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUserRemark 修改客户备注信息
|
// UpdateUserRemark 修改客户备注信息
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/92115
|
||||||
func (r *Client) UpdateUserRemark(request UpdateUserRemarkRequest) error {
|
func (r *Client) UpdateUserRemark(request UpdateUserRemarkRequest) error {
|
||||||
accessToken, err := r.GetAccessToken()
|
accessToken, err := r.GetAccessToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
143
work/externalcontact/groupchat.go
Normal file
143
work/externalcontact/groupchat.go
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
package externalcontact
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/v2/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OpengIDToChatIDURL 客户群opengid转换URL
|
||||||
|
const OpengIDToChatIDURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/opengid_to_chatid"
|
||||||
|
|
||||||
|
type (
|
||||||
|
//GroupChatListRequest 获取客户群列表的请求参数
|
||||||
|
GroupChatListRequest struct {
|
||||||
|
StatusFilter int `json:"status_filter"` // 非必填 客户群跟进状态过滤。0 - 所有列表(即不过滤) 1 - 离职待继承 2 - 离职继承中 3 - 离职继承完成
|
||||||
|
OwnerFilter OwnerFilter `json:"owner_filter"` //非必填 群主过滤。如果不填,表示获取应用可见范围内全部群主的数据(但是不建议这么用,如果可见范围人数超过1000人,为了防止数据包过大,会报错 81017)
|
||||||
|
Cursor string `json:"cursor"` //非必填 用于分页查询的游标,字符串类型,由上一次调用返回,首次调用不填
|
||||||
|
Limit int `json:"limit"` //必填 分页,预期请求的数据量,取值范围 1 ~ 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
//GroupChatList 客户群列表
|
||||||
|
GroupChatList struct {
|
||||||
|
ChatID string `json:"chat_id"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
}
|
||||||
|
//GroupChatListResponse 获取客户群列表的返回值
|
||||||
|
GroupChatListResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
GroupChatList []GroupChatList `json:"group_chat_list"`
|
||||||
|
NextCursor string `json:"next_cursor"` //游标
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetGroupChatList 获取客户群列表
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/92120
|
||||||
|
func (r *Client) GetGroupChatList(req *GroupChatListRequest) (*GroupChatListResponse, error) {
|
||||||
|
accessToken, err := r.GetAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
response, err = util.PostJSON(fmt.Sprintf("%s/list?access_token=%s", GroupChatURL, accessToken), req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &GroupChatListResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "GetGroupChatList"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
//GroupChatDetailRequest 客户群详情 请求参数
|
||||||
|
GroupChatDetailRequest struct {
|
||||||
|
ChatID string `json:"chat_id"`
|
||||||
|
NeedName int `json:"need_name"`
|
||||||
|
}
|
||||||
|
//Invitor 邀请者
|
||||||
|
Invitor struct {
|
||||||
|
UserID string `json:"userid"` //邀请者的userid
|
||||||
|
}
|
||||||
|
//GroupChatMember 群成员
|
||||||
|
GroupChatMember struct {
|
||||||
|
UserID string `json:"userid"` //群成员id
|
||||||
|
Type int `json:"type"` //成员类型。 1 - 企业成员 2 - 外部联系人
|
||||||
|
JoinTime int `json:"join_time"` //入群时间
|
||||||
|
JoinScene int `json:"join_scene"` //入群方式 1 - 由群成员邀请入群(直接邀请入群) 2 - 由群成员邀请入群(通过邀请链接入群) 3 - 通过扫描群二维码入群
|
||||||
|
Invitor Invitor `json:"invitor,omitempty"` //邀请者。目前仅当是由本企业内部成员邀请入群时会返回该值
|
||||||
|
GroupNickname string `json:"group_nickname"` //在群里的昵称
|
||||||
|
Name string `json:"name"` //名字。仅当 need_name = 1 时返回 如果是微信用户,则返回其在微信中设置的名字 如果是企业微信联系人,则返回其设置对外展示的别名或实名
|
||||||
|
UnionID string `json:"unionid,omitempty"` //外部联系人在微信开放平台的唯一身份标识(微信unionid),通过此字段企业可将外部联系人与公众号/小程序用户关联起来。仅当群成员类型是微信用户(包括企业成员未添加好友),且企业绑定了微信开发者ID有此字段(查看绑定方法)。第三方不可获取,上游企业不可获取下游企业客户的unionid字段
|
||||||
|
}
|
||||||
|
//GroupChatAdmin 群管理员
|
||||||
|
GroupChatAdmin struct {
|
||||||
|
UserID string `json:"userid"` //群管理员userid
|
||||||
|
}
|
||||||
|
//GroupChat 客户群详情
|
||||||
|
GroupChat struct {
|
||||||
|
ChatID string `json:"chat_id"` //客户群ID
|
||||||
|
Name string `json:"name"` //群名
|
||||||
|
Owner string `json:"owner"` //群主ID
|
||||||
|
CreateTime int `json:"create_time"` //群的创建时间
|
||||||
|
Notice string `json:"notice"` //群公告
|
||||||
|
MemberList []GroupChatMember `json:"member_list"` //群成员列表
|
||||||
|
AdminList []GroupChatAdmin `json:"admin_list"` //群管理员列表
|
||||||
|
}
|
||||||
|
//GroupChatDetailResponse 客户群详情 返回值
|
||||||
|
GroupChatDetailResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
GroupChat GroupChat `json:"group_chat"` //客户群详情
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetGroupChatDetail 获取客户群详情
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/92122
|
||||||
|
func (r *Client) GetGroupChatDetail(req *GroupChatDetailRequest) (*GroupChatDetailResponse, error) {
|
||||||
|
accessToken, err := r.GetAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
response, err = util.PostJSON(fmt.Sprintf("%s/get?access_token=%s", GroupChatURL, accessToken), req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &GroupChatDetailResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "GetGroupChatDetail"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
//OpengIDToChatIDRequest 客户群opengid转换 请求参数
|
||||||
|
OpengIDToChatIDRequest struct {
|
||||||
|
OpengID string `json:"opengid"`
|
||||||
|
}
|
||||||
|
//OpengIDToChatIDResponse 客户群opengid转换 返回值
|
||||||
|
OpengIDToChatIDResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
ChatID string `json:"chat_id"` //客户群ID
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// OpengIDToChatID 客户群opengid转换
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/94828
|
||||||
|
func (r *Client) OpengIDToChatID(req *OpengIDToChatIDRequest) (*OpengIDToChatIDResponse, error) {
|
||||||
|
accessToken, err := r.GetAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
response, err = util.PostJSON(fmt.Sprintf("%s?access_token=%s", OpengIDToChatIDURL, accessToken), req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &OpengIDToChatIDResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "GetGroupChatDetail"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
146
work/externalcontact/join_way.go
Normal file
146
work/externalcontact/join_way.go
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package externalcontact
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/v2/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupChatURL 客户群
|
||||||
|
const GroupChatURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat"
|
||||||
|
|
||||||
|
type (
|
||||||
|
// AddJoinWayRequest 添加群配置请求参数
|
||||||
|
AddJoinWayRequest struct {
|
||||||
|
Scene int `json:"scene"` // 必填 1 - 群的小程序插件,2 - 群的二维码插件
|
||||||
|
Remark string `json:"remark"` //非必填 联系方式的备注信息,用于助记,超过30个字符将被截断
|
||||||
|
AutoCreateRoom int `json:"auto_create_room"` //非必填 当群满了后,是否自动新建群。0-否;1-是。 默认为1
|
||||||
|
RoomBaseName string `json:"room_base_name"` //非必填 自动建群的群名前缀,当auto_create_room为1时有效。最长40个utf8字符
|
||||||
|
RoomBaseID int `json:"room_base_id"` //非必填 自动建群的群起始序号,当auto_create_room为1时有效
|
||||||
|
ChatIDList []string `json:"chat_id_list"` //必填 使用该配置的客户群ID列表,支持5个。见客户群ID获取方法
|
||||||
|
State string `json:"state"` //非必填 企业自定义的state参数,用于区分不同的入群渠道。不超过30个UTF-8字符
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddJoinWayResponse 添加群配置返回值
|
||||||
|
AddJoinWayResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
ConfigID string `json:"config_id"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddJoinWay 加入群聊
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/92229
|
||||||
|
func (r *Client) AddJoinWay(req *AddJoinWayRequest) (*AddJoinWayResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
response []byte
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response, err = util.PostJSON(fmt.Sprintf("%s/add_join_way?access_token=%s", GroupChatURL, accessToken), req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &AddJoinWayResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "AddJoinWay"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
//JoinWayConfigRequest 获取或删除群配置的请求参数
|
||||||
|
JoinWayConfigRequest struct {
|
||||||
|
ConfigID string `json:"config_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//JoinWay 群配置
|
||||||
|
JoinWay struct {
|
||||||
|
ConfigID string `json:"config_id"`
|
||||||
|
Scene int `json:"scene"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
AutoCreateRoom int `json:"auto_create_room"`
|
||||||
|
RoomBaseName string `json:"room_base_name"`
|
||||||
|
RoomBaseID int `json:"room_base_id"`
|
||||||
|
ChatIDList []string `json:"chat_id_list"`
|
||||||
|
QrCode string `json:"qr_code"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
//GetJoinWayResponse 获取群配置的返回值
|
||||||
|
GetJoinWayResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
JoinWay JoinWay `json:"join_way"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetJoinWay 获取客户群进群方式配置
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/92229
|
||||||
|
func (r *Client) GetJoinWay(req *JoinWayConfigRequest) (*GetJoinWayResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
response []byte
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response, err = util.PostJSON(fmt.Sprintf("%s/get_join_way?access_token=%s", GroupChatURL, accessToken), req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &GetJoinWayResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "GetJoinWay"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateJoinWayRequest 更新群配置的请求参数
|
||||||
|
type UpdateJoinWayRequest struct {
|
||||||
|
ConfigID string `json:"config_id"`
|
||||||
|
Scene int `json:"scene"` // 必填 1 - 群的小程序插件,2 - 群的二维码插件
|
||||||
|
Remark string `json:"remark"` //非必填 联系方式的备注信息,用于助记,超过30个字符将被截断
|
||||||
|
AutoCreateRoom int `json:"auto_create_room"` //非必填 当群满了后,是否自动新建群。0-否;1-是。 默认为1
|
||||||
|
RoomBaseName string `json:"room_base_name"` //非必填 自动建群的群名前缀,当auto_create_room为1时有效。最长40个utf8字符
|
||||||
|
RoomBaseID int `json:"room_base_id"` //非必填 自动建群的群起始序号,当auto_create_room为1时有效
|
||||||
|
ChatIDList []string `json:"chat_id_list"` //必填 使用该配置的客户群ID列表,支持5个。见客户群ID获取方法
|
||||||
|
State string `json:"state"` //非必填 企业自定义的state参数,用于区分不同的入群渠道。不超过30个UTF-8字符
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateJoinWay 更新客户群进群方式配置
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/92229
|
||||||
|
func (r *Client) UpdateJoinWay(req *UpdateJoinWayRequest) error {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
response []byte
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
response, err = util.PostJSON(fmt.Sprintf("%s/update_join_way?access_token=%s", GroupChatURL, accessToken), req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return util.DecodeWithCommonError(response, "UpdateJoinWay")
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelJoinWay 删除客户群进群方式配置
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/92229
|
||||||
|
func (r *Client) DelJoinWay(req *JoinWayConfigRequest) error {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
response []byte
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
response, err = util.PostJSON(fmt.Sprintf("%s/del_join_way?access_token=%s", GroupChatURL, accessToken), req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return util.DecodeWithCommonError(response, "DelJoinWay")
|
||||||
|
}
|
||||||
424
work/externalcontact/msg.go
Normal file
424
work/externalcontact/msg.go
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
package externalcontact
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/v2/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AddMsgTemplateURL 创建企业群发
|
||||||
|
AddMsgTemplateURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_msg_template?access_token=%s"
|
||||||
|
// GetGroupMsgListV2URL 获取群发记录列表
|
||||||
|
GetGroupMsgListV2URL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_list_v2?access_token=%s"
|
||||||
|
// GetGroupMsgTaskURL 获取群发成员发送任务列表
|
||||||
|
GetGroupMsgTaskURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_task?access_token=%s"
|
||||||
|
// GetGroupMsgSendResultURL 获取企业群发成员执行结果
|
||||||
|
GetGroupMsgSendResultURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_send_result?access_token=%s"
|
||||||
|
// SendWelcomeMsgURL 发送新客户欢迎语
|
||||||
|
SendWelcomeMsgURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/send_welcome_msg?access_token=%s"
|
||||||
|
// AddGroupWelcomeTemplateURL 添加入群欢迎语素材
|
||||||
|
AddGroupWelcomeTemplateURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/add?access_token=%s"
|
||||||
|
// EditGroupWelcomeTemplateURL 编辑入群欢迎语素材
|
||||||
|
EditGroupWelcomeTemplateURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/edit?access_token=%s"
|
||||||
|
// GetGroupWelcomeTemplateURL 获取入群欢迎语素材
|
||||||
|
GetGroupWelcomeTemplateURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/get?access_token=%s"
|
||||||
|
// DelGroupWelcomeTemplateURL 删除入群欢迎语素材
|
||||||
|
DelGroupWelcomeTemplateURL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/del?access_token=%s"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddMsgTemplateRequest 创建企业群发请求
|
||||||
|
type AddMsgTemplateRequest struct {
|
||||||
|
ChatType string `json:"chat_type"`
|
||||||
|
ExternalUserID []string `json:"external_userid"`
|
||||||
|
Sender string `json:"sender,omitempty"`
|
||||||
|
Text MsgText `json:"text"`
|
||||||
|
Attachments []*Attachment `json:"attachments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgText 文本消息
|
||||||
|
type MsgText struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Attachment 附件
|
||||||
|
Attachment struct {
|
||||||
|
MsgType string `json:"msgtype"`
|
||||||
|
Image AttachmentImg `json:"image,omitempty"`
|
||||||
|
Link AttachmentLink `json:"link,omitempty"`
|
||||||
|
MiniProgram AttachmentMiniProgram `json:"miniprogram,omitempty"`
|
||||||
|
Video AttachmentVideo `json:"video,omitempty"`
|
||||||
|
File AttachmentFile `json:"file,omitempty"`
|
||||||
|
}
|
||||||
|
// AttachmentImg 图片消息
|
||||||
|
AttachmentImg struct {
|
||||||
|
MediaID string `json:"media_id"`
|
||||||
|
PicURL string `json:"pic_url"`
|
||||||
|
}
|
||||||
|
// AttachmentLink 图文消息
|
||||||
|
AttachmentLink struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
PicURL string `json:"picurl"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
// AttachmentMiniProgram 小程序消息
|
||||||
|
AttachmentMiniProgram struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
PicMediaID string `json:"pic_media_id"`
|
||||||
|
AppID string `json:"appid"`
|
||||||
|
Page string `json:"page"`
|
||||||
|
}
|
||||||
|
// AttachmentVideo 视频消息
|
||||||
|
AttachmentVideo struct {
|
||||||
|
MediaID string `json:"media_id"`
|
||||||
|
}
|
||||||
|
// AttachmentFile 文件消息
|
||||||
|
AttachmentFile struct {
|
||||||
|
MediaID string `json:"media_id"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddMsgTemplateResponse 创建企业群发响应
|
||||||
|
type AddMsgTemplateResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
FailList []string `json:"fail_list"`
|
||||||
|
MsgID string `json:"msgid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMsgTemplate 创建企业群发
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/92135
|
||||||
|
func (r *Client) AddMsgTemplate(req *AddMsgTemplateRequest) (*AddMsgTemplateResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(AddMsgTemplateURL, accessToken), req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &AddMsgTemplateResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "AddMsgTemplate"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgListV2Request 获取群发记录列表请求
|
||||||
|
type GetGroupMsgListV2Request struct {
|
||||||
|
ChatType string `json:"chat_type"`
|
||||||
|
StartTime int `json:"start_time"`
|
||||||
|
EndTime int `json:"end_time"`
|
||||||
|
Creator string `json:"creator,omitempty"`
|
||||||
|
FilterType int `json:"filter_type"`
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
Cursor string `json:"cursor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgListV2Response 获取群发记录列表响应
|
||||||
|
type GetGroupMsgListV2Response struct {
|
||||||
|
util.CommonError
|
||||||
|
NextCursor string `json:"next_cursor"`
|
||||||
|
GroupMsgList []*GroupMsg `json:"group_msg_list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupMsg 群发消息
|
||||||
|
type GroupMsg struct {
|
||||||
|
MsgID string `json:"msgid"`
|
||||||
|
Creator string `json:"creator"`
|
||||||
|
CreateTime int `json:"create_time"`
|
||||||
|
CreateType int `json:"create_type"`
|
||||||
|
Text MsgText `json:"text"`
|
||||||
|
Attachments []*Attachment `json:"attachments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgListV2 获取群发记录列表
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/93338#%E8%8E%B7%E5%8F%96%E7%BE%A4%E5%8F%91%E8%AE%B0%E5%BD%95%E5%88%97%E8%A1%A8
|
||||||
|
func (r *Client) GetGroupMsgListV2(req *GetGroupMsgListV2Request) (*GetGroupMsgListV2Response, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(GetGroupMsgListV2URL, accessToken), req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &GetGroupMsgListV2Response{}
|
||||||
|
if err = util.DecodeWithError(response, result, "GetGroupMsgListV2"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgTaskRequest 获取群发成员发送任务列表请求
|
||||||
|
type GetGroupMsgTaskRequest struct {
|
||||||
|
MsgID string `json:"msgid"`
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
Cursor string `json:"cursor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgTaskResponse 获取群发成员发送任务列表响应
|
||||||
|
type GetGroupMsgTaskResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
NextCursor string `json:"next_cursor"`
|
||||||
|
TaskList []*Task `json:"task_list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task 获取群发成员发送任务列表任务
|
||||||
|
type Task struct {
|
||||||
|
UserID string `json:"userid"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
SendTime int `json:"send_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgTask 获取群发成员发送任务列表
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/93338#%E8%8E%B7%E5%8F%96%E7%BE%A4%E5%8F%91%E6%88%90%E5%91%98%E5%8F%91%E9%80%81%E4%BB%BB%E5%8A%A1%E5%88%97%E8%A1%A8
|
||||||
|
func (r *Client) GetGroupMsgTask(req *GetGroupMsgTaskRequest) (*GetGroupMsgTaskResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(GetGroupMsgTaskURL, accessToken), req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &GetGroupMsgTaskResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "GetGroupMsgTask"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgSendResultRequest 获取企业群发成员执行结果请求
|
||||||
|
type GetGroupMsgSendResultRequest struct {
|
||||||
|
MsgID string `json:"msgid"`
|
||||||
|
UserID string `json:"userid"`
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
Cursor string `json:"cursor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgSendResultResponse 获取企业群发成员执行结果响应
|
||||||
|
type GetGroupMsgSendResultResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
NextCursor string `json:"next_cursor"`
|
||||||
|
SendList []*Send `json:"send_list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send 企业群发成员执行结果
|
||||||
|
type Send struct {
|
||||||
|
ExternalUserID string `json:"external_userid"`
|
||||||
|
ChatID string `json:"chat_id"`
|
||||||
|
UserID string `json:"userid"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
SendTime int `json:"send_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupMsgSendResult 获取企业群发成员执行结果
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/93338#%E8%8E%B7%E5%8F%96%E4%BC%81%E4%B8%9A%E7%BE%A4%E5%8F%91%E6%88%90%E5%91%98%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C
|
||||||
|
func (r *Client) GetGroupMsgSendResult(req *GetGroupMsgSendResultRequest) (*GetGroupMsgSendResultResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(GetGroupMsgSendResultURL, accessToken), req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &GetGroupMsgSendResultResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "GetGroupMsgSendResult"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendWelcomeMsgRequest 发送新客户欢迎语请求
|
||||||
|
type SendWelcomeMsgRequest struct {
|
||||||
|
WelcomeCode string `json:"welcome_code"`
|
||||||
|
Text MsgText `json:"text"`
|
||||||
|
Attachments []*Attachment `json:"attachments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendWelcomeMsgResponse 发送新客户欢迎语响应
|
||||||
|
type SendWelcomeMsgResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendWelcomeMsg 发送新客户欢迎语
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/92137
|
||||||
|
func (r *Client) SendWelcomeMsg(req *SendWelcomeMsgRequest) error {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(SendWelcomeMsgURL, accessToken), req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
result := &SendWelcomeMsgResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "SendWelcomeMsg"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupWelcomeTemplateRequest 添加入群欢迎语素材请求
|
||||||
|
type AddGroupWelcomeTemplateRequest struct {
|
||||||
|
Text MsgText `json:"text"`
|
||||||
|
Image AttachmentImg `json:"image"`
|
||||||
|
Link AttachmentLink `json:"link"`
|
||||||
|
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||||
|
File AttachmentFile `json:"file"`
|
||||||
|
Video AttachmentVideo `json:"video"`
|
||||||
|
AgentID int `json:"agentid"`
|
||||||
|
Notify int `json:"notify"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupWelcomeTemplateResponse 添加入群欢迎语素材响应
|
||||||
|
type AddGroupWelcomeTemplateResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
TemplateID string `json:"template_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroupWelcomeTemplate 添加入群欢迎语素材
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/92366#%E6%B7%BB%E5%8A%A0%E5%85%A5%E7%BE%A4%E6%AC%A2%E8%BF%8E%E8%AF%AD%E7%B4%A0%E6%9D%90
|
||||||
|
func (r *Client) AddGroupWelcomeTemplate(req *AddGroupWelcomeTemplateRequest) (*AddGroupWelcomeTemplateResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(AddGroupWelcomeTemplateURL, accessToken), req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &AddGroupWelcomeTemplateResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "AddGroupWelcomeTemplate"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupWelcomeTemplateRequest 编辑入群欢迎语素材请求
|
||||||
|
type EditGroupWelcomeTemplateRequest struct {
|
||||||
|
TemplateID string `json:"template_id"`
|
||||||
|
Text MsgText `json:"text"`
|
||||||
|
Image AttachmentImg `json:"image"`
|
||||||
|
Link AttachmentLink `json:"link"`
|
||||||
|
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||||
|
File AttachmentFile `json:"file"`
|
||||||
|
Video AttachmentVideo `json:"video"`
|
||||||
|
AgentID int `json:"agentid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupWelcomeTemplateResponse 编辑入群欢迎语素材响应
|
||||||
|
type EditGroupWelcomeTemplateResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditGroupWelcomeTemplate 编辑入群欢迎语素材
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/92366#%E7%BC%96%E8%BE%91%E5%85%A5%E7%BE%A4%E6%AC%A2%E8%BF%8E%E8%AF%AD%E7%B4%A0%E6%9D%90
|
||||||
|
func (r *Client) EditGroupWelcomeTemplate(req *EditGroupWelcomeTemplateRequest) error {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(EditGroupWelcomeTemplateURL, accessToken), req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
result := &EditGroupWelcomeTemplateResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "EditGroupWelcomeTemplate"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupWelcomeTemplateRequest 获取入群欢迎语素材请求
|
||||||
|
type GetGroupWelcomeTemplateRequest struct {
|
||||||
|
TemplateID string `json:"template_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupWelcomeTemplateResponse 获取入群欢迎语素材响应
|
||||||
|
type GetGroupWelcomeTemplateResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
Text MsgText `json:"text"`
|
||||||
|
Image AttachmentImg `json:"image"`
|
||||||
|
Link AttachmentLink `json:"link"`
|
||||||
|
MiniProgram AttachmentMiniProgram `json:"miniprogram"`
|
||||||
|
File AttachmentFile `json:"file"`
|
||||||
|
Video AttachmentVideo `json:"video"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupWelcomeTemplate 获取入群欢迎语素材
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/92366#%E8%8E%B7%E5%8F%96%E5%85%A5%E7%BE%A4%E6%AC%A2%E8%BF%8E%E8%AF%AD%E7%B4%A0%E6%9D%90
|
||||||
|
func (r *Client) GetGroupWelcomeTemplate(req *GetGroupWelcomeTemplateRequest) (*GetGroupWelcomeTemplateResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(GetGroupWelcomeTemplateURL, accessToken), req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &GetGroupWelcomeTemplateResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "GetGroupWelcomeTemplate"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelGroupWelcomeTemplateRequest 删除入群欢迎语素材请求
|
||||||
|
type DelGroupWelcomeTemplateRequest struct {
|
||||||
|
TemplateID string `json:"template_id"`
|
||||||
|
AgentID int `json:"agentid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelGroupWelcomeTemplateResponse 删除入群欢迎语素材响应
|
||||||
|
type DelGroupWelcomeTemplateResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelGroupWelcomeTemplate 删除入群欢迎语素材
|
||||||
|
// see https://developer.work.weixin.qq.com/document/path/92366#%E5%88%A0%E9%99%A4%E5%85%A5%E7%BE%A4%E6%AC%A2%E8%BF%8E%E8%AF%AD%E7%B4%A0%E6%9D%90
|
||||||
|
func (r *Client) DelGroupWelcomeTemplate(req *DelGroupWelcomeTemplateRequest) error {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostJSON(fmt.Sprintf(DelGroupWelcomeTemplateURL, accessToken), req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
result := &DelGroupWelcomeTemplateResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "DelGroupWelcomeTemplate"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
17
work/material/client.go
Normal file
17
work/material/client.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package material
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/silenceper/wechat/v2/work/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client 素材管理接口实例
|
||||||
|
type Client struct {
|
||||||
|
*context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient 初始化实例
|
||||||
|
func NewClient(ctx *context.Context) *Client {
|
||||||
|
return &Client{
|
||||||
|
ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
39
work/material/media.go
Normal file
39
work/material/media.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package material
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/silenceper/wechat/v2/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UploadImgURL 上传图片
|
||||||
|
UploadImgURL = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg?access_token=%s"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UploadImgResponse 上传图片响应
|
||||||
|
type UploadImgResponse struct {
|
||||||
|
util.CommonError
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadImg 上传图片
|
||||||
|
// @see https://developer.work.weixin.qq.com/document/path/90256
|
||||||
|
func (r *Client) UploadImg(filename string) (*UploadImgResponse, error) {
|
||||||
|
var (
|
||||||
|
accessToken string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if accessToken, err = r.GetAccessToken(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var response []byte
|
||||||
|
if response, err = util.PostFile("media", filename, fmt.Sprintf(UploadImgURL, accessToken)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := &UploadImgResponse{}
|
||||||
|
if err = util.DecodeWithError(response, result, "UploadImg"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/silenceper/wechat/v2/work/context"
|
"github.com/silenceper/wechat/v2/work/context"
|
||||||
"github.com/silenceper/wechat/v2/work/externalcontact"
|
"github.com/silenceper/wechat/v2/work/externalcontact"
|
||||||
"github.com/silenceper/wechat/v2/work/kf"
|
"github.com/silenceper/wechat/v2/work/kf"
|
||||||
|
"github.com/silenceper/wechat/v2/work/material"
|
||||||
"github.com/silenceper/wechat/v2/work/msgaudit"
|
"github.com/silenceper/wechat/v2/work/msgaudit"
|
||||||
"github.com/silenceper/wechat/v2/work/oauth"
|
"github.com/silenceper/wechat/v2/work/oauth"
|
||||||
"github.com/silenceper/wechat/v2/work/robot"
|
"github.com/silenceper/wechat/v2/work/robot"
|
||||||
@@ -57,6 +58,11 @@ func (wk *Work) GetAddressList() *addresslist.Client {
|
|||||||
return addresslist.NewClient(wk.ctx)
|
return addresslist.NewClient(wk.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMaterial get material
|
||||||
|
func (wk *Work) GetMaterial() *material.Client {
|
||||||
|
return material.NewClient(wk.ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// GetRobot get robot
|
// GetRobot get robot
|
||||||
func (wk *Work) GetRobot() *robot.Client {
|
func (wk *Work) GetRobot() *robot.Client {
|
||||||
return robot.NewClient(wk.ctx)
|
return robot.NewClient(wk.ctx)
|
||||||
|
|||||||
Reference in New Issue
Block a user