forked from chanxuehong/wechat
/
client_user.go
380 lines (323 loc) · 8.44 KB
/
client_user.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
package wechat
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/chanxuehong/wechat/user"
"net/http"
)
// 创建分组
func (c *Client) UserGroupCreate(name string) (*user.Group, error) {
if len(name) == 0 {
return nil, errors.New(`UserGroupCreate: UserGroupCreate: name == ""`)
}
token, err := c.Token()
if err != nil {
return nil, err
}
var request struct {
Group struct {
Name string `json:"name"`
} `json:"group"`
}
request.Group.Name = name
jsonData, err := json.Marshal(&request)
if err != nil {
return nil, err
}
_url := clientUserGroupCreateURL(token)
resp, err := c.httpClient.Post(_url, postJSONContentType, bytes.NewReader(jsonData))
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("UserGroupCreate: %s", resp.Status)
}
var result struct {
Group struct {
Id int `json:"id"`
Name string `json:"name"`
} `json:"group"`
Error
}
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
if result.ErrCode != 0 {
return nil, &result.Error
}
var group user.Group
group.Id = result.Group.Id
group.Name = result.Group.Name
return &group, nil
}
// 查询所有分组
func (c *Client) UserGroupGet() ([]user.Group, error) {
token, err := c.Token()
if err != nil {
return nil, err
}
_url := clientUserGroupGetURL(token)
resp, err := c.httpClient.Get(_url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("UserGroupGet: %s", resp.Status)
}
var result struct {
Groups []user.Group `json:"groups"`
Error
}
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
if result.ErrCode != 0 {
return nil, &result.Error
}
return result.Groups, nil
}
// 修改分组名
func (c *Client) UserGroupRename(groupid int, name string) (err error) {
if len(name) == 0 {
return errors.New(`UserGroupRename: name == ""`)
}
token, err := c.Token()
if err != nil {
return
}
var request struct {
Group struct {
Id int `json:"id"`
Name string `json:"name"`
} `json:"group"`
}
request.Group.Id = groupid
request.Group.Name = name
jsonData, err := json.Marshal(&request)
if err != nil {
return
}
_url := clientUserGroupRenameURL(token)
resp, err := c.httpClient.Post(_url, postJSONContentType, bytes.NewReader(jsonData))
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("UserGroupRename: %s", resp.Status)
}
var result Error
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
return
}
if result.ErrCode != 0 {
return &result
}
return
}
// 查询用户所在分组
func (c *Client) UserInWhichGroup(openid string) (groupid int, err error) {
if len(openid) == 0 {
err = errors.New(`UserInWhichGroup: openid == ""`)
return
}
token, err := c.Token()
if err != nil {
return
}
var request = struct {
OpenId string `json:"openid"`
}{OpenId: openid}
jsonData, err := json.Marshal(&request)
if err != nil {
return
}
_url := clientUserInWhichGroupURL(token)
resp, err := c.httpClient.Post(_url, postJSONContentType, bytes.NewReader(jsonData))
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
err = fmt.Errorf("UserInWhichGroup: %s", resp.Status)
return
}
var result struct {
GroupId int `json:"groupid"`
Error
}
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
return
}
if result.ErrCode != 0 {
err = &result.Error
return
}
groupid = result.GroupId
return
}
// 移动用户分组
func (c *Client) UserMoveToGroup(openid string, toGroupId int) (err error) {
if len(openid) == 0 {
return errors.New(`UserMoveToGroup: openid == ""`)
}
token, err := c.Token()
if err != nil {
return
}
var request = struct {
OpenId string `json:"openid"`
ToGroupId int `json:"to_groupid"`
}{
OpenId: openid,
ToGroupId: toGroupId,
}
jsonData, err := json.Marshal(&request)
if err != nil {
return
}
_url := clientUserMoveToGroupURL(token)
resp, err := c.httpClient.Post(_url, postJSONContentType, bytes.NewReader(jsonData))
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
err = fmt.Errorf("UserMoveToGroup: %s", resp.Status)
return
}
var result Error
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
return
}
if result.ErrCode != 0 {
return &result
}
return
}
// 获取用户基本信息.
// lang 可能的取值是 zh_CN, zh_TW, en; 如果留空 "" 则默认为 zh_CN.
func (c *Client) UserInfo(openid string, lang string) (*user.UserInfo, error) {
if len(openid) == 0 {
return nil, errors.New(`UserInfo: openid == ""`)
}
switch lang {
case "":
lang = user.Language_zh_CN
case user.Language_zh_CN, user.Language_zh_TW, user.Language_en:
default:
return nil, errors.New(`UserInfo: lang 必须是 "", zh_CN, zh_TW, en 之一`)
}
token, err := c.Token()
if err != nil {
return nil, err
}
_url := clientUserInfoURL(token, openid, lang)
resp, err := c.httpClient.Get(_url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("UserInfo: %s", resp.Status)
}
var result struct {
// 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
Subscribe int `json:"subscribe"`
user.UserInfo
Error
}
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
if result.ErrCode != 0 {
return nil, &result.Error
}
if result.Subscribe == 0 {
return nil, fmt.Errorf("UserInfo: 该用户 %s 没有订阅这个公众号", openid)
}
return &result.UserInfo, nil
}
// 获取关注者返回的数据结构
type userGetResponse struct {
TotalCount int `json:"total"` // 关注该公众账号的总用户数
GetCount int `json:"count"` // 拉取的OPENID个数,最大值为10000
Data struct {
OpenId []string `json:"openid"`
} `json:"data"` // 列表数据,OPENID的列表
// 拉取列表的后一个用户的OPENID, 如果 next_openid == "" 则表示没有了用户数据
NextOpenId string `json:"next_openid"`
}
// 获取关注者列表, 如果 beginOpenId == "" 则表示从头遍历
func (c *Client) userGet(beginOpenId string) (*userGetResponse, error) {
token, err := c.Token()
if err != nil {
return nil, err
}
_url := clientUserGetURL(token, beginOpenId)
resp, err := c.httpClient.Get(_url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("userGet: %s", resp.Status)
}
var result struct {
userGetResponse
Error
}
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
if result.ErrCode != 0 {
return nil, &result.Error
}
return &result.userGetResponse, nil
}
// 该结构实现了 user.UserIterator 接口
type userGetIterator struct {
userGetResponse *userGetResponse // 对于 HasNext() 表示上次返回的数据
wechatClient *Client // 关联的微信 Client
nextPageCalled bool // NextPage() 是否调用过
}
func (iter *userGetIterator) Total() int {
return iter.userGetResponse.TotalCount
}
func (iter *userGetIterator) HasNext() bool {
// 第一批数据不需要通过 NextPage() 来获取, 因为在创建这个对象的时候就获取了;
// 后续的数据都要通过 NextPage() 来获取, 所以要通过上一次的 NextOpenId 来判断了.
if !iter.nextPageCalled {
return iter.userGetResponse.GetCount > 0
}
return iter.userGetResponse.NextOpenId != ""
}
func (iter *userGetIterator) NextPage() ([]string, error) {
// 第一次调用 NextPage(), 因为在创建这个对象的时候已经获取了数据, 所以直接返回.
if !iter.nextPageCalled {
iter.nextPageCalled = true
return iter.userGetResponse.Data.OpenId, nil
}
// 不是第一次调用的都要从服务器拉取数据
resp, err := iter.wechatClient.userGet(iter.userGetResponse.NextOpenId)
if err != nil {
return nil, err
}
iter.userGetResponse = resp // 覆盖老数据
return resp.Data.OpenId, nil
}
// 关注用户遍历器, 如果 beginOpenId == "" 则表示从头遍历
func (c *Client) UserIterator(beginOpenId string) (user.UserIterator, error) {
resp, err := c.userGet(beginOpenId)
if err != nil {
return nil, err
}
var iter userGetIterator
iter.userGetResponse = resp
iter.wechatClient = c
return &iter, nil
}