-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbots.go
425 lines (301 loc) · 8.1 KB
/
bots.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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
package dbl
import (
"bytes"
"encoding/json"
"strconv"
"strings"
"time"
)
type Bot struct {
// The id of the bot
ID string `json:"id"`
// The username of the bot
Username string `json:"username"`
// The discriminator of the bot
Discriminator string `json:"discriminator"`
// The avatar hash of the bot's avatar (may be empty)
Avatar string `json:"avatar"`
// The cdn hash of the bot's avatar if the bot has none
DefAvatar string `json:"defAvatar"`
// The library of the bot
Library string `json:"lib"`
// The prefix of the bot
Prefix string `json:"prefix"`
// The short description of the bot
ShortDescription string `json:"shortdesc"`
// The long description of the bot. Can contain HTML and/or Markdown (may be empty)
LongDescription string `json:"longdesc"`
// The tags of the bot
Tags []string `json:"tags"`
// The website url of the bot (may be empty)
Website string `json:"website"`
// The support server invite code of the bot (may be empty)
Support string `json:"support"`
// The link to the github repo of the bot (may be empty)
Github string `json:"github"`
// The owners of the bot. First one in the array is the main owner
Owners []string `json:"owners"`
// The custom bot invite url of the bot (may be empty)
Invite string `json:"invite"`
// The date when the bot was approved
Date time.Time `json:"date"`
// The certified status of the bot
CertifiedBot bool `json:"certifiedBot"`
// The vanity url of the bot (deprecated) (may be empty)
Vanity string `json:"vanity"`
// The monthly amount of upvotes the bot has (undocumented)
MonthlyPoints int `json:"monthlyPoints"`
// The amount of upvotes the bot has
Points int `json:"points"`
// The GuildID for the donate bot (undocumented) (may be empty)
DonateBotGuildID string `json:"donatebotguildid"`
// The amount of servers the bot is in (undocumented)
ServerCount int `json:"server_count"`
// Server affiliation ("Servers this bot is in" field) (undocumented)
GuildAffiliation []string `json:"guilds"`
// The amount of servers the bot is in per shard. Always present but can be empty (undocumented)
Shards []int `json:"shards"`
}
type GetBotsPayload struct {
// The amount of bots to return. Max. 500
// Default 50
Limit int
// Amount of bots to skip
// Default 0
Offset int
// Field search filter
Search map[string]string
// The field to sort by. Prefix with "-" to reverse the order
Sort string
// A list of fields to show
Fields []string
}
type GetBotsResult struct {
// Slice of Bot pointers of matching bots
Results []*Bot `json:"results"`
// The limit used
Limit int `json:"limit"`
// The offset used
Offset int `json:"offset"`
// The length of the results array
Count int `json:"count"`
// The total number of bots matching your search
// Not limited by "limit" field
Total int `json:"total"`
}
type BotStats struct {
// The amount of servers the bot is in (may be empty)
ServerCount int `json:"server_count"`
// The amount of servers the bot is in per shard. Always present but can be empty
Shards []int `json:"shards"`
// The amount of shards a bot has (may be empty)
ShardCount int `json:"shard_count"`
}
type checkResponse struct {
Voted int `json:"voted"`
}
type BotStatsPayload struct {
// The amount of servers the bot is in per shard.
Shards []int `json:"shards"`
// The zero-indexed id of the shard posting. Makes server_count set the shard specific server count (optional)
ShardID int `json:"shard_id"`
// The amount of shards the bot has (optional)
ShardCount int `json:"shard_count"`
}
// Information about different bots with an optional filter parameter
//
// Use nil if no option is passed
func (c *Client) GetBots(filter *GetBotsPayload) (*GetBotsResult, error) {
if c.token == "" {
return nil, ErrRequireAuthentication
}
if !c.limiter.Allow() {
return nil, ErrLocalRatelimit
}
req, err := c.createRequest("GET", "bots", nil)
if filter != nil {
q := req.URL.Query()
if filter.Limit != 0 {
q.Add("limit", strconv.Itoa(filter.Limit))
}
if filter.Offset != 0 {
q.Add("offset", strconv.Itoa(filter.Offset))
}
if len(filter.Search) != 0 {
tStack := make([]string, 0)
for f, v := range filter.Search {
tStack = append(tStack, f+": "+v)
}
q.Add("search", strings.Join(tStack, " "))
}
if filter.Sort != "" {
q.Add("sort", filter.Sort)
}
if len(filter.Fields) != 0 {
q.Add("fields", strings.Join(filter.Fields, ","))
}
req.URL.RawQuery = q.Encode()
}
res, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
body, err := c.readBody(res)
if err != nil {
return nil, err
}
bots := &GetBotsResult{}
err = json.Unmarshal(body, bots)
if err != nil {
return nil, err
}
return bots, nil
}
// Information about a specific bot
func (c *Client) GetBot(botID string) (*Bot, error) {
if c.token == "" {
return nil, ErrRequireAuthentication
}
if !c.limiter.Allow() {
return nil, ErrLocalRatelimit
}
req, err := c.createRequest("GET", "bots/"+botID, nil)
if err != nil {
return nil, err
}
res, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
body, err := c.readBody(res)
if err != nil {
return nil, err
}
bot := &Bot{}
err = json.Unmarshal(body, bot)
if err != nil {
return nil, err
}
return bot, nil
}
// Use this endpoint to see who have upvoted your bot
//
// Requires authentication
//
// IF YOU HAVE OVER 1000 VOTES PER MONTH YOU HAVE TO USE THE WEBHOOKS AND CAN NOT USE THIS
func (c *Client) GetVotes(botID string) ([]*User, error) {
if c.token == "" {
return nil, ErrRequireAuthentication
}
if !c.limiter.Allow() {
return nil, ErrLocalRatelimit
}
req, err := c.createRequest("GET", "bots/"+botID+"/votes", nil)
if err != nil {
return nil, err
}
res, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
body, err := c.readBody(res)
if err != nil {
return nil, err
}
users := make([]*User, 0)
err = json.Unmarshal(body, users)
if err != nil {
return nil, err
}
return users, nil
}
// Use this endpoint to see who have upvoted your bot in the past 24 hours. It is safe to use this even if you have over 1k votes.
//
// Requires authentication
func (c *Client) HasUserVoted(botID, userID string) (bool, error) {
if c.token == "" {
return false, ErrRequireAuthentication
}
if !c.limiter.Allow() {
return false, ErrLocalRatelimit
}
req, err := c.createRequest("GET", "bots/"+botID+"/check", nil)
if err != nil {
return false, err
}
q := req.URL.Query()
q.Add("userId", userID)
req.URL.RawQuery = q.Encode()
res, err := c.httpClient.Do(req)
if err != nil {
return false, err
}
body, err := c.readBody(res)
if err != nil {
return false, err
}
cr := &checkResponse{}
err = json.Unmarshal(body, cr)
if err != nil {
return false, err
}
return cr.Voted == 1, nil
}
// Information about a specific bot's stats
func (c *Client) GetBotStats(botID string) (*BotStats, error) {
if c.token == "" {
return nil, ErrRequireAuthentication
}
if !c.limiter.Allow() {
return nil, ErrLocalRatelimit
}
req, err := c.createRequest("GET", "bots/"+botID+"/stats", nil)
if err != nil {
return nil, err
}
res, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
body, err := c.readBody(res)
if err != nil {
return nil, err
}
botStats := &BotStats{}
err = json.Unmarshal(body, botStats)
if err != nil {
return nil, err
}
return botStats, nil
}
// Post your bot's stats
//
// Requires authentication
//
// If your bot is unsharded, pass in server count as the only item in the slice
func (c *Client) PostBotStats(botID string, payload *BotStatsPayload) error {
if c.token == "" {
return ErrRequireAuthentication
}
if !c.limiter.Allow() {
return ErrLocalRatelimit
}
encoded, err := json.Marshal(payload)
if err != nil {
return err
}
req, err := c.createRequest("POST", "bots/"+botID+"/stats", bytes.NewBuffer(encoded))
if err != nil {
return err
}
req.Header.Set("Authorization", c.token)
req.Header.Set("Content-Type", "application/json")
res, err := c.httpClient.Do(req)
if err != nil {
return err
}
if res.StatusCode != 200 {
return ErrRequestFailed
}
return nil
}