2020-01-16 04:27:57 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2020-10-28 22:39:59 +00:00
|
|
|
"github.com/diamondburned/arikawa/v2/discord"
|
|
|
|
"github.com/diamondburned/arikawa/v2/utils/httputil"
|
|
|
|
"github.com/diamondburned/arikawa/v2/utils/json/option"
|
2020-01-16 04:27:57 +00:00
|
|
|
)
|
|
|
|
|
2020-10-19 14:47:43 +00:00
|
|
|
const maxMemberFetchLimit = 1000
|
|
|
|
|
|
|
|
// Member returns a guild member object for the specified user.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) Member(guildID discord.GuildID, userID discord.UserID) (*discord.Member, error) {
|
2020-01-18 19:34:08 +00:00
|
|
|
var m *discord.Member
|
2020-05-12 02:05:08 +00:00
|
|
|
return m, c.RequestJSON(&m, "GET", EndpointGuilds+guildID.String()+"/members/"+userID.String())
|
2020-01-18 19:34:08 +00:00
|
|
|
}
|
|
|
|
|
2020-05-16 23:35:57 +00:00
|
|
|
// 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
|
2020-10-19 14:47:43 +00:00
|
|
|
// limit is set to 0, has fetched all members in the guild.
|
2020-05-11 22:06:19 +00:00
|
|
|
//
|
2020-05-16 23:35:57 +00:00
|
|
|
// 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
|
2020-10-19 14:47:43 +00:00
|
|
|
// they may be less if no more members are available.
|
2020-05-16 23:35:57 +00:00
|
|
|
//
|
|
|
|
// When fetching the members, those with the smallest ID will be fetched first.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) Members(guildID discord.GuildID, limit uint) ([]discord.Member, error) {
|
2020-05-16 23:35:57 +00:00
|
|
|
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
|
2020-10-19 14:47:43 +00:00
|
|
|
// limit is set to 0, has fetched all members with an id higher than after.
|
2020-05-16 23:35:57 +00:00
|
|
|
//
|
|
|
|
// 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(
|
2020-07-21 20:27:59 +00:00
|
|
|
guildID discord.GuildID, after discord.UserID, limit uint) ([]discord.Member, error) {
|
2020-05-16 23:35:57 +00:00
|
|
|
|
2020-10-19 14:47:43 +00:00
|
|
|
mems := make([]discord.Member, 0, limit)
|
2020-01-16 04:27:57 +00:00
|
|
|
|
2020-10-19 14:47:43 +00:00
|
|
|
fetch := uint(maxMemberFetchLimit)
|
2020-01-16 04:27:57 +00:00
|
|
|
|
2020-05-16 23:35:57 +00:00
|
|
|
unlimited := limit == 0
|
2020-05-11 22:06:19 +00:00
|
|
|
|
2020-10-19 14:47:43 +00:00
|
|
|
for limit > 0 || unlimited {
|
|
|
|
// Only fetch as much as we need. Since limit gradually decreases,
|
|
|
|
// we only need to fetch min(fetch, limit).
|
2020-05-16 23:35:57 +00:00
|
|
|
if limit > 0 {
|
2020-11-21 14:53:57 +00:00
|
|
|
fetch = uint(min(maxMemberFetchLimit, int(limit)))
|
2020-05-16 23:35:57 +00:00
|
|
|
limit -= fetch
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
2020-05-16 23:35:57 +00:00
|
|
|
m, err := c.membersAfter(guildID, after, fetch)
|
2020-01-16 04:27:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return mems, err
|
|
|
|
}
|
|
|
|
mems = append(mems, m...)
|
|
|
|
|
2020-05-16 23:35:57 +00:00
|
|
|
// There aren't any to fetch, even if this is less than limit.
|
2020-10-19 14:47:43 +00:00
|
|
|
if len(m) < maxMemberFetchLimit {
|
2020-01-16 04:27:57 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2020-05-22 22:59:27 +00:00
|
|
|
after = mems[len(mems)-1].User.ID
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 14:47:43 +00:00
|
|
|
if len(mems) == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2020-01-16 04:27:57 +00:00
|
|
|
return mems, nil
|
|
|
|
}
|
|
|
|
|
2020-05-16 23:35:57 +00:00
|
|
|
func (c *Client) membersAfter(
|
2020-07-21 20:27:59 +00:00
|
|
|
guildID discord.GuildID, after discord.UserID, limit uint) ([]discord.Member, error) {
|
2020-01-16 04:27:57 +00:00
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
switch {
|
|
|
|
case limit == 0:
|
|
|
|
limit = 0
|
|
|
|
case limit > 1000:
|
2020-01-16 04:27:57 +00:00
|
|
|
limit = 1000
|
|
|
|
}
|
|
|
|
|
|
|
|
var param struct {
|
2020-07-21 20:27:59 +00:00
|
|
|
After discord.UserID `schema:"after,omitempty"`
|
|
|
|
Limit uint `schema:"limit"`
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
param.Limit = limit
|
|
|
|
param.After = after
|
|
|
|
|
|
|
|
var mems []discord.Member
|
|
|
|
return mems, c.RequestJSON(
|
|
|
|
&mems, "GET",
|
|
|
|
EndpointGuilds+guildID.String()+"/members",
|
|
|
|
httputil.WithSchema(c, param),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// 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.
|
2020-05-11 01:14:30 +00:00
|
|
|
Nick option.String `json:"nick,omitempty"`
|
2020-05-11 22:06:19 +00:00
|
|
|
// Roles is an array of role ids the member is assigned.
|
|
|
|
//
|
|
|
|
// Requires MANAGE_ROLES.
|
2020-07-21 20:27:59 +00:00
|
|
|
Roles *[]discord.RoleID `json:"roles,omitempty"`
|
2020-05-11 22:06:19 +00:00
|
|
|
// 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"`
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// 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.
|
2020-01-16 04:27:57 +00:00
|
|
|
func (c *Client) AddMember(
|
2020-07-21 20:27:59 +00:00
|
|
|
guildID discord.GuildID, userID discord.UserID, data AddMemberData) (*discord.Member, error) {
|
2020-01-16 04:27:57 +00:00
|
|
|
var mem *discord.Member
|
|
|
|
return mem, c.RequestJSON(
|
|
|
|
&mem, "PUT",
|
|
|
|
EndpointGuilds+guildID.String()+"/members/"+userID.String(),
|
2020-05-11 22:06:19 +00:00
|
|
|
httputil.WithJSONBody(data),
|
2020-01-16 04:27:57 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// 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.
|
2020-07-21 20:27:59 +00:00
|
|
|
Roles *[]discord.RoleID `json:"roles,omitempty"`
|
2020-05-11 22:06:19 +00:00
|
|
|
// 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
|
2020-07-21 20:27:59 +00:00
|
|
|
VoiceChannel discord.ChannelID `json:"channel_id,omitempty"`
|
2020-05-11 22:06:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) ModifyMember(guildID discord.GuildID, userID discord.UserID, data ModifyMemberData) error {
|
2020-01-16 04:27:57 +00:00
|
|
|
|
|
|
|
return c.FastRequest(
|
|
|
|
"PATCH",
|
|
|
|
EndpointGuilds+guildID.String()+"/members/"+userID.String(),
|
2020-05-08 03:43:46 +00:00
|
|
|
httputil.WithJSONBody(data),
|
2020-01-16 04:27:57 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-22 19:05:24 +00:00
|
|
|
// https://discord.com/developers/docs/resources/guild#get-guild-prune-count-query-string-params
|
|
|
|
type PruneCountData struct {
|
2020-07-12 01:51:01 +00:00
|
|
|
// Days is the number of days to count prune for (1 or more, default 7).
|
2020-05-22 19:05:24 +00:00
|
|
|
Days uint `schema:"days"`
|
|
|
|
// IncludedRoles are the role(s) to include.
|
2020-07-21 20:27:59 +00:00
|
|
|
IncludedRoles []discord.RoleID `schema:"include_roles,omitempty"`
|
2020-05-22 19:05:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 04:27:57 +00:00
|
|
|
// PruneCount returns the number of members that would be removed in a prune
|
2020-05-11 22:06:19 +00:00
|
|
|
// operation. Days must be 1 or more, default 7.
|
|
|
|
//
|
2020-05-22 19:05:24 +00:00
|
|
|
// 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.
|
|
|
|
//
|
2020-05-11 22:06:19 +00:00
|
|
|
// Requires KICK_MEMBERS.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) PruneCount(guildID discord.GuildID, data PruneCountData) (uint, error) {
|
2020-05-22 19:05:24 +00:00
|
|
|
if data.Days == 0 {
|
|
|
|
data.Days = 7
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var resp struct {
|
|
|
|
Pruned uint `json:"pruned"`
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp.Pruned, c.RequestJSON(
|
|
|
|
&resp, "GET",
|
|
|
|
EndpointGuilds+guildID.String()+"/prune",
|
2020-05-22 19:05:24 +00:00
|
|
|
httputil.WithSchema(c, data),
|
2020-01-16 04:27:57 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-22 19:05:24 +00:00
|
|
|
// https://discord.com/developers/docs/resources/guild#begin-guild-prune-query-string-params
|
|
|
|
type PruneData struct {
|
2020-07-12 01:51:01 +00:00
|
|
|
// Days is the number of days to prune (1 or more, default 7).
|
2020-05-22 19:05:24 +00:00
|
|
|
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.
|
2020-07-21 20:27:59 +00:00
|
|
|
IncludedRoles []discord.RoleID `schema:"include_roles,omitempty"`
|
2020-05-12 03:15:50 +00:00
|
|
|
}
|
|
|
|
|
2020-05-22 19:05:24 +00:00
|
|
|
// 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.
|
2020-05-11 22:06:19 +00:00
|
|
|
//
|
|
|
|
// Requires KICK_MEMBERS.
|
2020-05-22 19:05:24 +00:00
|
|
|
// Fires multiple Guild Member Remove Gateway events.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) Prune(guildID discord.GuildID, data PruneData) (uint, error) {
|
2020-05-22 19:05:24 +00:00
|
|
|
if data.Days == 0 {
|
|
|
|
data.Days = 7
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var resp struct {
|
|
|
|
Pruned uint `json:"pruned"`
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp.Pruned, c.RequestJSON(
|
|
|
|
&resp, "POST",
|
|
|
|
EndpointGuilds+guildID.String()+"/prune",
|
2020-05-22 19:05:24 +00:00
|
|
|
httputil.WithSchema(c, data),
|
2020-01-16 04:27:57 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// Kick removes a member from a guild.
|
|
|
|
//
|
|
|
|
// Requires KICK_MEMBERS permission.
|
|
|
|
// Fires a Guild Member Remove Gateway event.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) Kick(guildID discord.GuildID, userID discord.UserID) error {
|
2020-08-22 16:51:10 +00:00
|
|
|
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
|
|
|
|
|
2020-05-12 02:05:08 +00:00
|
|
|
return c.FastRequest(
|
|
|
|
"DELETE",
|
|
|
|
EndpointGuilds+guildID.String()+"/members/"+userID.String(),
|
2020-08-22 16:51:10 +00:00
|
|
|
httputil.WithSchema(c, data),
|
2020-05-12 02:05:08 +00:00
|
|
|
)
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// Bans returns a list of ban objects for the users banned from this guild.
|
|
|
|
//
|
|
|
|
// Requires the BAN_MEMBERS permission.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) Bans(guildID discord.GuildID) ([]discord.Ban, error) {
|
2020-01-16 04:27:57 +00:00
|
|
|
var bans []discord.Ban
|
2020-05-12 02:05:08 +00:00
|
|
|
return bans, c.RequestJSON(
|
|
|
|
&bans, "GET",
|
|
|
|
EndpointGuilds+guildID.String()+"/bans",
|
|
|
|
)
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// GetBan returns a ban object for the given user.
|
|
|
|
//
|
|
|
|
// Requires the BAN_MEMBERS permission.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) GetBan(guildID discord.GuildID, userID discord.UserID) (*discord.Ban, error) {
|
2020-01-16 04:27:57 +00:00
|
|
|
var ban *discord.Ban
|
2020-05-12 02:05:08 +00:00
|
|
|
return ban, c.RequestJSON(
|
|
|
|
&ban, "GET",
|
|
|
|
EndpointGuilds+guildID.String()+"/bans/"+userID.String(),
|
|
|
|
)
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// 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"`
|
|
|
|
}
|
2020-01-16 04:27:57 +00:00
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// Ban creates a guild ban, and optionally delete previous messages sent by the
|
|
|
|
// banned user.
|
|
|
|
//
|
|
|
|
// Requires the BAN_MEMBERS permission.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) Ban(guildID discord.GuildID, userID discord.UserID, data BanData) error {
|
2020-01-16 04:27:57 +00:00
|
|
|
return c.FastRequest(
|
|
|
|
"PUT",
|
|
|
|
EndpointGuilds+guildID.String()+"/bans/"+userID.String(),
|
2020-05-11 22:06:19 +00:00
|
|
|
httputil.WithSchema(c, data),
|
2020-01-16 04:27:57 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-11 22:06:19 +00:00
|
|
|
// Unban removes the ban for a user.
|
|
|
|
//
|
|
|
|
// Requires the BAN_MEMBERS permissions.
|
|
|
|
// Fires a Guild Ban Remove Gateway event.
|
2020-07-21 20:27:59 +00:00
|
|
|
func (c *Client) Unban(guildID discord.GuildID, userID discord.UserID) error {
|
2020-05-07 19:32:56 +00:00
|
|
|
return c.FastRequest("DELETE", EndpointGuilds+guildID.String()+"/bans/"+userID.String())
|
2020-01-16 04:27:57 +00:00
|
|
|
}
|