/
member.go
331 lines (288 loc) · 10.3 KB
/
member.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
package api
import (
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/utils/httputil"
"github.com/diamondburned/arikawa/utils/json/option"
)
const maxMemberFetchLimit = 1000
// Member returns a guild member object for the specified user.
func (c *Client) Member(guildID discord.GuildID, userID discord.UserID) (*discord.Member, error) {
var m *discord.Member
return m, c.RequestJSON(&m, "GET", EndpointGuilds+guildID.String()+"/members/"+userID.String())
}
// Members returns a list of members of the guild with the passed id. This
// method automatically paginates until it reaches the passed limit, or, if the
// limit is set to 0, has fetched all members in the guild.
//
// As the underlying endpoint has a maximum of 1000 members per request, at
// maximum a total of limit/1000 rounded up requests will be made, although
// they may be less if no more members are available.
//
// When fetching the members, those with the smallest ID will be fetched first.
func (c *Client) Members(guildID discord.GuildID, limit uint) ([]discord.Member, error) {
return c.MembersAfter(guildID, 0, limit)
}
// MembersAfter returns a list of members of the guild with the passed id. This
// method automatically paginates until it reaches the passed limit, or, if the
// limit is set to 0, has fetched all members with an id higher than after.
//
// As the underlying endpoint has a maximum of 1000 members per request, at
// maximum a total of limit/1000 rounded up requests will be made, although
// they may be less, if no more members are available.
func (c *Client) MembersAfter(
guildID discord.GuildID, after discord.UserID, limit uint) ([]discord.Member, error) {
mems := make([]discord.Member, 0, limit)
fetch := uint(maxMemberFetchLimit)
unlimited := limit == 0
for limit > 0 || unlimited {
// Only fetch as much as we need. Since limit gradually decreases,
// we only need to fetch min(fetch, limit).
if limit > 0 {
if fetch > limit {
fetch = limit
}
limit -= fetch
}
m, err := c.membersAfter(guildID, after, fetch)
if err != nil {
return mems, err
}
mems = append(mems, m...)
// There aren't any to fetch, even if this is less than limit.
if len(m) < maxMemberFetchLimit {
break
}
after = mems[len(mems)-1].User.ID
}
if len(mems) == 0 {
return nil, nil
}
return mems, nil
}
func (c *Client) membersAfter(
guildID discord.GuildID, after discord.UserID, limit uint) ([]discord.Member, error) {
switch {
case limit == 0:
limit = 0
case limit > 1000:
limit = 1000
}
var param struct {
After discord.UserID `schema:"after,omitempty"`
Limit uint `schema:"limit"`
}
param.Limit = limit
param.After = after
var mems []discord.Member
return mems, c.RequestJSON(
&mems, "GET",
EndpointGuilds+guildID.String()+"/members",
httputil.WithSchema(c, param),
)
}
// https://discord.com/developers/docs/resources/guild#add-guild-member-json-params
type AddMemberData struct {
// Token is an oauth2 access token granted with the guilds.join to the
// bot's application for the user you want to add to the guild.
Token string `json:"access_token"`
// Nick is the value to set users nickname to.
//
// Requires MANAGE_NICKNAMES.
Nick option.String `json:"nick,omitempty"`
// Roles is an array of role ids the member is assigned.
//
// Requires MANAGE_ROLES.
Roles *[]discord.RoleID `json:"roles,omitempty"`
// Mute specifies whether the user is muted in voice channels.
//
// Requires MUTE_MEMBERS.
Mute option.Bool `json:"mute,omitempty"`
// Deaf specifies whether the user is deafened in voice channels.
//
// Requires DEAFEN_MEMBERS.
Deaf option.Bool `json:"deaf,omitempty"`
}
// AddMember adds a user to the guild, provided you have a valid oauth2 access
// token for the user with the guilds.join scope. Returns a 201 Created with
// the guild member as the body, or 204 No Content if the user is already a
// member of the guild.
//
// Fires a Guild Member Add Gateway event.
//
// The Authorization header must be a Bot token (belonging to the same
// application used for authorization), and the bot must be a member of the
// guild with CREATE_INSTANT_INVITE permission.
func (c *Client) AddMember(
guildID discord.GuildID, userID discord.UserID, data AddMemberData) (*discord.Member, error) {
var mem *discord.Member
return mem, c.RequestJSON(
&mem, "PUT",
EndpointGuilds+guildID.String()+"/members/"+userID.String(),
httputil.WithJSONBody(data),
)
}
// https://discord.com/developers/docs/resources/guild#add-guild-member-json-params
type ModifyMemberData struct {
// Nick is the value to set users nickname to.
//
// Requires MANAGE_NICKNAMES.
Nick option.String `json:"nick,omitempty"`
// Roles is an array of role ids the member is assigned.
//
// Requires MANAGE_ROLES.
Roles *[]discord.RoleID `json:"roles,omitempty"`
// Mute specifies whether the user is muted in voice channels.
//
// Requires MUTE_MEMBERS.
Mute option.Bool `json:"mute,omitempty"`
// Deaf specifies whether the user is deafened in voice channels.
//
// Requires DEAFEN_MEMBERS.
Deaf option.Bool `json:"deaf,omitempty"`
// Voice channel is the id of channel to move user to (if they are
// connected to voice).
//
// Requires MOVE_MEMBER
VoiceChannel discord.ChannelID `json:"channel_id,omitempty"`
}
// ModifyMember modifies attributes of a guild member. If the channel_id is set
// to null, this will force the target user to be disconnected from voice.
//
// Fires a Guild Member Update Gateway event.
func (c *Client) ModifyMember(guildID discord.GuildID, userID discord.UserID, data ModifyMemberData) error {
return c.FastRequest(
"PATCH",
EndpointGuilds+guildID.String()+"/members/"+userID.String(),
httputil.WithJSONBody(data),
)
}
// https://discord.com/developers/docs/resources/guild#get-guild-prune-count-query-string-params
type PruneCountData struct {
// Days is the number of days to count prune for (1 or more, default 7).
Days uint `schema:"days"`
// IncludedRoles are the role(s) to include.
IncludedRoles []discord.RoleID `schema:"include_roles,omitempty"`
}
// PruneCount returns the number of members that would be removed in a prune
// operation. Days must be 1 or more, default 7.
//
// By default, prune will not remove users with roles. You can optionally
// include specific roles in your prune by providing the IncludedRoles
// parameter. Any inactive user that has a subset of the provided role(s)
// will be counted in the prune and users with additional roles will not.
//
// Requires KICK_MEMBERS.
func (c *Client) PruneCount(guildID discord.GuildID, data PruneCountData) (uint, error) {
if data.Days == 0 {
data.Days = 7
}
var resp struct {
Pruned uint `json:"pruned"`
}
return resp.Pruned, c.RequestJSON(
&resp, "GET",
EndpointGuilds+guildID.String()+"/prune",
httputil.WithSchema(c, data),
)
}
// https://discord.com/developers/docs/resources/guild#begin-guild-prune-query-string-params
type PruneData struct {
// Days is the number of days to prune (1 or more, default 7).
Days uint `schema:"days"`
// ReturnCount specifies whether 'pruned' is returned. Discouraged for
// large guilds.
ReturnCount bool `schema:"compute_prune_count"`
// IncludedRoles are the role(s) to include.
IncludedRoles []discord.RoleID `schema:"include_roles,omitempty"`
}
// Prune begins a prune. Days must be 1 or more, default 7.
//
// By default, prune will not remove users with roles. You can optionally
// include specific roles in your prune by providing the IncludedRoles
// parameter. Any inactive user that has a subset of the provided role(s)
// will be included in the prune and users with additional roles will not.
//
// Requires KICK_MEMBERS.
// Fires multiple Guild Member Remove Gateway events.
func (c *Client) Prune(guildID discord.GuildID, data PruneData) (uint, error) {
if data.Days == 0 {
data.Days = 7
}
var resp struct {
Pruned uint `json:"pruned"`
}
return resp.Pruned, c.RequestJSON(
&resp, "POST",
EndpointGuilds+guildID.String()+"/prune",
httputil.WithSchema(c, data),
)
}
// Kick removes a member from a guild.
//
// Requires KICK_MEMBERS permission.
// Fires a Guild Member Remove Gateway event.
func (c *Client) Kick(guildID discord.GuildID, userID discord.UserID) error {
return c.KickWithReason(guildID, userID, "")
}
// KickWithReason removes a member from a guild.
// The reason, if non-empty, will be displayed in the audit log of the guild.
//
// Requires KICK_MEMBERS permission.
// Fires a Guild Member Remove Gateway event.
func (c *Client) KickWithReason(
guildID discord.GuildID, userID discord.UserID, reason string) error {
var data struct {
Reason string `schema:"reason,omitempty"`
}
data.Reason = reason
return c.FastRequest(
"DELETE",
EndpointGuilds+guildID.String()+"/members/"+userID.String(),
httputil.WithSchema(c, data),
)
}
// Bans returns a list of ban objects for the users banned from this guild.
//
// Requires the BAN_MEMBERS permission.
func (c *Client) Bans(guildID discord.GuildID) ([]discord.Ban, error) {
var bans []discord.Ban
return bans, c.RequestJSON(
&bans, "GET",
EndpointGuilds+guildID.String()+"/bans",
)
}
// GetBan returns a ban object for the given user.
//
// Requires the BAN_MEMBERS permission.
func (c *Client) GetBan(guildID discord.GuildID, userID discord.UserID) (*discord.Ban, error) {
var ban *discord.Ban
return ban, c.RequestJSON(
&ban, "GET",
EndpointGuilds+guildID.String()+"/bans/"+userID.String(),
)
}
// https://discord.com/developers/docs/resources/guild#create-guild-ban-query-string-params
type BanData struct {
// DeleteDays is the number of days to delete messages for (0-7).
DeleteDays option.Uint `schema:"delete_message_days,omitempty"`
// Reason is the reason for the ban.
Reason option.String `schema:"reason,omitempty"`
}
// Ban creates a guild ban, and optionally delete previous messages sent by the
// banned user.
//
// Requires the BAN_MEMBERS permission.
func (c *Client) Ban(guildID discord.GuildID, userID discord.UserID, data BanData) error {
return c.FastRequest(
"PUT",
EndpointGuilds+guildID.String()+"/bans/"+userID.String(),
httputil.WithSchema(c, data),
)
}
// Unban removes the ban for a user.
//
// Requires the BAN_MEMBERS permissions.
// Fires a Guild Ban Remove Gateway event.
func (c *Client) Unban(guildID discord.GuildID, userID discord.UserID) error {
return c.FastRequest("DELETE", EndpointGuilds+guildID.String()+"/bans/"+userID.String())
}