From 04a80d33e8dc0966d3887fd0ad29836ef0d62f48 Mon Sep 17 00:00:00 2001 From: mavolin <48887425+mavolin@users.noreply.github.com> Date: Tue, 12 May 2020 00:06:19 +0200 Subject: [PATCH] API: add docs, use option types --- api/channel.go | 193 +++++++++++++++++-------- api/emoji.go | 76 +++++----- api/guild.go | 275 +++++++++++++++++++++++++++--------- api/invite.go | 67 +++++---- api/member.go | 169 ++++++++++++++-------- api/message.go | 87 ++++++++---- api/message_reaction.go | 66 +++++---- api/role.go | 92 ++++++++---- api/send.go | 57 ++++++-- api/user.go | 26 +++- api/webhook.go | 59 ++++++-- discord/message.go | 17 ++- discord/permission.go | 64 ++++----- utils/json/option/custom.go | 50 ++++++- utils/json/option/number.go | 2 +- 15 files changed, 908 insertions(+), 392 deletions(-) diff --git a/api/channel.go b/api/channel.go index da49e5b..e6e6f0a 100644 --- a/api/channel.go +++ b/api/channel.go @@ -8,36 +8,67 @@ import ( var EndpointChannels = Endpoint + "channels/" -func (c *Client) Channels( - guildID discord.Snowflake) ([]discord.Channel, error) { - +// Channels returns a list of guild channel objects. +func (c *Client) Channels(guildID discord.Snowflake) ([]discord.Channel, error) { var chs []discord.Channel - return chs, c.RequestJSON(&chs, "GET", - EndpointGuilds+guildID.String()+"/channels") + return chs, c.RequestJSON(&chs, "GET", EndpointGuilds+guildID.String()+"/channels") } +// https://discord.com/developers/docs/resources/guild#create-guild-channel-json-params type CreateChannelData struct { - Name string `json:"name"` // 2-100 - Topic string `json:"topic,omitempty"` - + // Name is the channel name (2-100 characters). + // + // Channel Type: All + Name string `json:"name"` + // Type is the type of channel. + // + // Channel Type: All Type discord.ChannelType `json:"type,omitempty"` - - VoiceBitrate uint `json:"bitrate,omitempty"` + // Topic is the channel topic (0-1024 characters). + // + // Channel Types: Text, News + Topic string `json:"topic,omitempty"` + // VoiceBitrate is the bitrate (in bits) of the voice channel. + // 8000 to 96000 (128000 for VIP servers) + // + // Channel Types: Voice + VoiceBitrate uint `json:"bitrate,omitempty"` + // VoiceUserLimit is the user limit of the voice channel. + // 0 refers to no limit, 1 to 99 refers to a user limit. + // + // Channel Types: Voice VoiceUserLimit uint `json:"user_limit,omitempty"` - + // UserRateLimit is the amount of seconds a user has to wait before sending + // another message (0-21600). + // Bots, as well as users with the permission manage_messages or + // manage_channel, are unaffected. + // + // Channel Types: Text UserRateLimit discord.Seconds `json:"rate_limit_per_user,omitempty"` - - NSFW bool `json:"nsfw,omitempty"` + // Position is the sorting position of the channel. + // + // Channel Types: All Position option.Int `json:"position,omitempty"` - + // Permissions are the channel's permission overwrites. + // + // Channel Types: All Permissions []discord.Overwrite `json:"permission_overwrites,omitempty"` - CategoryID discord.Snowflake `json:"parent_id,string,omitempty"` + // CategoryID is the id of the parent category for a channel. + // + // Channel Types: Text, News, Store, Voice + CategoryID discord.Snowflake `json:"parent_id,string,omitempty"` + // NSFW specifies whether the channel is nsfw. + // + // Channel Types: Text, News, Store. + NSFW bool `json:"nsfw,omitempty"` } +// CreateChannel creates a new channel object for the guild. +// +// Requires the MANAGE_CHANNELS permission. +// Fires a Channel Create Gateway event. func (c *Client) CreateChannel( - guildID discord.Snowflake, - data CreateChannelData) (*discord.Channel, error) { - + guildID discord.Snowflake, data CreateChannelData) (*discord.Channel, error) { var ch *discord.Channel return ch, c.RequestJSON( &ch, "POST", @@ -47,62 +78,99 @@ func (c *Client) CreateChannel( } type MoveChannelData struct { - ID discord.Snowflake `json:"id"` - Position option.Int `json:"position"` + // ID is the channel id. + ID discord.Snowflake `json:"id"` + // Position is the sorting position of the channel + Position option.Int `json:"position"` } -// MoveChannel modifies the position of channels in the guild. Requires -// MANAGE_CHANNELS. +// MoveChannel modifies the position of channels in the guild. +// +// Requires MANAGE_CHANNELS. func (c *Client) MoveChannel(guildID discord.Snowflake, datum []MoveChannelData) error { return c.FastRequest( "PATCH", - EndpointGuilds+guildID.String()+"/channels", - httputil.WithJSONBody(datum), + EndpointGuilds+guildID.String()+"/channels", httputil.WithJSONBody(datum), ) } +// Channel gets a channel by ID. Returns a channel object. func (c *Client) Channel(channelID discord.Snowflake) (*discord.Channel, error) { var channel *discord.Channel return channel, c.RequestJSON(&channel, "GET", EndpointChannels+channelID.String()) } +// https://discord.com/developers/docs/resources/channel#modify-channel-json-params type ModifyChannelData struct { - // All types + // Name is the 2-100 character channel name. + // + // Channel Types: All Name string `json:"name,omitempty"` - // Type allows conversions between text and news channels. - Type *discord.ChannelType `json:"type,omitempty"` - Position option.Int `json:"position,omitempty"` + // Type is the type of the channel. + // Only conversion between text and news is supported and only in guilds + // with the "NEWS" feature + // + // Channel Types: Text, News + Type *discord.ChannelType `json:"type,omitempty"` + // Postion is the position of the channel in the left-hand listing + // + // Channel Types: All + Position option.NullableInt `json:"position,omitempty"` + // Topic is the 0-1024 character channel topic. + // + // Channel Types: Text, News + Topic option.NullableString `json:"topic,omitempty"` + // NSFW specifies whether the channel is nsfw. + // + // Channel Types: Text, News, Store. + NSFW option.NullableBool `json:"nsfw,omitempty"` + // UserRateLimit is the amount of seconds a user has to wait before sending + // another message (0-21600). + // Bots, as well as users with the permission manage_messages or + // manage_channel, are unaffected. + // + // Channel Types: Text + UserRateLimit option.NullableUint `json:"rate_limit_per_user,omitempty"` + // VoiceBitrate is the bitrate (in bits) of the voice channel. + // 8000 to 96000 (128000 for VIP servers) + // + // Channel Types: Voice + VoiceBitrate option.NullableUint `json:"bitrate,omitempty"` + // VoiceUserLimit is the user limit of the voice channel. + // 0 refers to no limit, 1 to 99 refers to a user limit. + // + // Channel Types: Voice + VoiceUserLimit option.NullableUint `json:"user_limit,omitempty"` + // Permissions are the channel or category-specific permissions. + // + // Channel Types: All Permissions *[]discord.Overwrite `json:"permission_overwrites,omitempty"` - - // Text only - Topic option.String `json:"topic,omitempty"` - NSFW option.Bool `json:"nsfw,omitempty"` - - // 0-21600 seconds, refer to (discord.Channel).UserRateLimit. - UserRateLimit option.Int `json:"rate_limit_per_user,omitempty"` - - // Voice only - // 8000 - 96000 (or 128000 for Nitro) - VoiceBitrate option.Uint `json:"bitrate,omitempty"` - // 0 no limit, 1-99 - VoiceUserLimit option.Uint `json:"user_limit,omitempty"` - - // Text OR Voice + // CategoryID is the id of the new parent category for a channel. + // Channel Types: Text, News, Store, Voice CategoryID discord.Snowflake `json:"parent_id,string,omitempty"` } +// ModifyChannel updates a channel's settings. +// +// Requires the MANAGE_CHANNELS permission for the guild. func (c *Client) ModifyChannel(channelID discord.Snowflake, data ModifyChannelData) error { - return c.FastRequest( - "PATCH", - EndpointChannels+channelID.String(), - httputil.WithJSONBody(data), - ) + return c.FastRequest("PATCH", EndpointChannels+channelID.String(), httputil.WithJSONBody(data)) } +// DeleteChannel deletes a channel, or closes a private message. Requires the +// MANAGE_CHANNELS permission for the guild. Deleting a category does not +// delete its child channels: they will have their parent_id removed and a +// Channel Update Gateway event will fire for each of them. +// +// Fires a Channel Delete Gateway event. func (c *Client) DeleteChannel(channelID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointChannels+channelID.String()) } +// EditChannelPermission edits the channel's permission overwrites for a user +// or role in a channel. Only usable for guild channels. +// +// Requires the MANAGE_ROLES permission. func (c *Client) EditChannelPermission( channelID discord.Snowflake, overwrite discord.Overwrite) error { @@ -112,9 +180,15 @@ func (c *Client) EditChannelPermission( return c.FastRequest("PUT", url, httputil.WithJSONBody(overwrite)) } +// DeleteChannelPermission deletes a channel permission overwrite for a user or +// role in a channel. Only usable for guild channels. +// +// Requires the MANAGE_ROLES permission. func (c *Client) DeleteChannelPermission(channelID, overwriteID discord.Snowflake) error { - return c.FastRequest("DELETE", - EndpointChannels+channelID.String()+"/permissions/"+overwriteID.String()) + return c.FastRequest( + "DELETE", + EndpointChannels+channelID.String()+"/permissions/"+overwriteID.String(), + ) } // Typing posts a typing indicator to the channel. Undocumented, but the client @@ -123,17 +197,23 @@ func (c *Client) Typing(channelID discord.Snowflake) error { return c.FastRequest("POST", EndpointChannels+channelID.String()+"/typing") } +// PinnedMessages returns all pinned messages in the channel as an array of +// message objects. func (c *Client) PinnedMessages(channelID discord.Snowflake) ([]discord.Message, error) { var pinned []discord.Message return pinned, c.RequestJSON(&pinned, "GET", EndpointChannels+channelID.String()+"/pins") } -// PinMessage pins a message, which requires MANAGE_MESSAGES/ +// PinMessage pins a message in a channel. +// +// Requires the MANAGE_MESSAGES permission. func (c *Client) PinMessage(channelID, messageID discord.Snowflake) error { return c.FastRequest("PUT", EndpointChannels+channelID.String()+"/pins/"+messageID.String()) } -// UnpinMessage also requires MANAGE_MESSAGES. +// UnpinMessage deletes a pinned message in a channel. +// +// Requires the MANAGE_MESSAGES permission. func (c *Client) UnpinMessage(channelID, messageID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointChannels+channelID.String()+"/pins/"+messageID.String()) } @@ -161,8 +241,10 @@ func (c *Client) AddRecipient( // RemoveRecipient removes a user from a group direct message. func (c *Client) RemoveRecipient(channelID, userID discord.Snowflake) error { - return c.FastRequest("DELETE", - EndpointChannels+channelID.String()+"/recipients/"+userID.String()) + return c.FastRequest( + "DELETE", + EndpointChannels+channelID.String()+"/recipients/"+userID.String(), + ) } // Ack is the read state of a channel. This is undocumented. @@ -176,8 +258,7 @@ type Ack struct { func (c *Client) Ack(channelID, messageID discord.Snowflake, ack *Ack) error { return c.RequestJSON( ack, "POST", - EndpointChannels+channelID.String()+ - "/messages/"+messageID.String()+"/ack", + EndpointChannels+channelID.String()+"/messages/"+messageID.String()+"/ack", httputil.WithJSONBody(ack), ) } diff --git a/api/emoji.go b/api/emoji.go index e99e6f4..ec2102a 100644 --- a/api/emoji.go +++ b/api/emoji.go @@ -16,76 +16,74 @@ func FormatEmojiAPI(id discord.Snowflake, name string) string { return name + ":" + id.String() } -func (c *Client) Emojis( - guildID discord.Snowflake) ([]discord.Emoji, error) { - +// Emojis returns a list of emoji objects for the given guild. +func (c *Client) Emojis(guildID discord.Snowflake) ([]discord.Emoji, error) { var emjs []discord.Emoji - return emjs, c.RequestJSON(&emjs, "GET", - EndpointGuilds+guildID.String()+"/emojis") + return emjs, c.RequestJSON(&emjs, "GET", EndpointGuilds+guildID.String()+"/emojis") } -func (c *Client) Emoji( - guildID, emojiID discord.Snowflake) (*discord.Emoji, error) { - +// Emoji returns an emoji object for the given guild and emoji IDs. +func (c *Client) Emoji(guildID, emojiID discord.Snowflake) (*discord.Emoji, error) { var emj *discord.Emoji return emj, c.RequestJSON(&emj, "GET", EndpointGuilds+guildID.String()+"/emojis/"+emojiID.String()) } +// https://discord.com/developers/docs/resources/emoji#create-guild-emoji-json-params +type CreateEmojiData struct { + // Name is the name of the emoji. + Name string `json:"name"` + // Image is the the 128x128 emoji image. + Image Image `json:"image"` + // Roles are the roles for which this emoji will be whitelisted. + Roles *[]discord.Snowflake `json:"roles,omitempty"` +} + // CreateEmoji creates a new emoji in the guild. This endpoint requires // MANAGE_EMOJIS. ContentType must be "image/jpeg", "image/png", or // "image/gif". However, ContentType can also be automatically detected -// (though shouldn't be relied on). Roles slice is optional. +// (though shouldn't be relied on). +// Emojis and animated emojis have a maximum file size of 256kb. func (c *Client) CreateEmoji( - guildID discord.Snowflake, name string, image Image, - roles []discord.Snowflake) (*discord.Emoji, error) { + guildID discord.Snowflake, data CreateEmojiData) (*discord.Emoji, error) { // Max 256KB - if err := image.Validate(256 * 1000); err != nil { + if err := data.Image.Validate(256 * 1000); err != nil { return nil, err } - var param struct { - Name string `json:"name"` - Image Image `json:"image"` - Roles []discord.Snowflake `json:"roles"` - } - - param.Name = name - param.Roles = roles - param.Image = image - var emj *discord.Emoji return emj, c.RequestJSON( &emj, "POST", EndpointGuilds+guildID.String()+"/emojis", - httputil.WithJSONBody(param), + httputil.WithJSONBody(data), ) } +// https://discord.com/developers/docs/resources/emoji#modify-guild-emoji-json-params +type ModifyEmojiData struct { + // Name is the name of the emoji. + Name string `json:"name,omitempty"` + // Roles are the roles to which this emoji will be whitelisted. + Roles *[]discord.Snowflake `json:"roles,omitempty"` +} + // ModifyEmoji changes an existing emoji. This requires MANAGE_EMOJIS. Name and // roles are optional fields (though you'd want to change either though). -func (c *Client) ModifyEmoji( - guildID, emojiID discord.Snowflake, name string, - roles []discord.Snowflake) error { - - var param struct { - Name string `json:"name,omitempty"` - Roles []discord.Snowflake `json:"roles,omitempty"` - } - - param.Name = name - param.Roles = roles - +// +// Fires a Guild Emojis Update Gateway event. +func (c *Client) ModifyEmoji(guildID, emojiID discord.Snowflake, data ModifyEmojiData) error { return c.FastRequest( "PATCH", EndpointGuilds+guildID.String()+"/emojis/"+emojiID.String(), - httputil.WithJSONBody(param), + httputil.WithJSONBody(data), ) } -// DeleteEmoji requires MANAGE_EMOJIS. +// Delete the given emoji. +// +// Requires the MANAGE_EMOJIS permission. +// Fires a Guild Emojis Update Gateway event. func (c *Client) DeleteEmoji(guildID, emojiID discord.Snowflake) error { - return c.FastRequest("DELETE", - EndpointGuilds+guildID.String()+"/emojis/"+emojiID.String()) + return c.FastRequest("DELETE", EndpointGuilds+guildID.String()+"/emojis/"+emojiID.String()) } diff --git a/api/guild.go b/api/guild.go index 0d67394..a8189a9 100644 --- a/api/guild.go +++ b/api/guild.go @@ -13,39 +13,78 @@ var EndpointGuilds = Endpoint + "guilds/" // https://discordapp.com/developers/docs/resources/guild#create-guild-json-params type CreateGuildData struct { + // Name is the name of the guild (2-100 characters) Name string `json:"name"` - Icon Image `json:"image,omitempty"` - - // package dc is just package discord - Verification *discord.Verification `json:"verification_level"` - Notification *discord.Notification `json:"default_message_notifications"` - ExplicitFilter *discord.ExplicitFilter `json:"explicit_content_filter"` - - // [0] (First entry) is ALWAYS @everyone. - Roles []discord.Role `json:"roles,omitempty"` - - // Voice only + // VoiceRegion is the voice region id. VoiceRegion string `json:"region,omitempty"` + // Icon is the base64 128x128 image for the guild icon. + Icon *Image `json:"image,omitempty"` - // Partial, id field is ignored. Usually only Name and Type are changed. + // Verification is the verification level. + Verification *discord.Verification `json:"verification_level,omitempty"` + // Notification is the default message notification level. + Notification *discord.Notification `json:"default_message_notifications,omitempty"` + // ExplicitFilter is the explicit content filter level. + ExplicitFilter *discord.ExplicitFilter `json:"explicit_content_filter,omitempty"` + + // Roles are the new guild roles. + // + // When using the roles parameter, the first member of the array is used to + // change properties of the guild's @everyone role. If you are trying to + // bootstrap a guild with additional roles, keep this in mind. + // + // When using the roles parameter, the required id field within each role + // object is an integer placeholder, and will be replaced by the API upon + // consumption. Its purpose is to allow you to overwrite a role's + // permissions in a channel when also passing in channels with the channels + // array. + Roles []discord.Role `json:"roles,omitempty"` + // Channels are the new guild's channels. + // Assigning a channel to a channel category is not supported by this + // endpoint, i.e. a channel can't have the parent_id field. + // + // When using the channels parameter, the position field is ignored, + // and none of the default channels are created. + // + // When using the channels parameter, the id field within each channel + // object may be set to an integer placeholder, and will be replaced by the + // API upon consumption. Its purpose is to allow you to create + // GUILD_CATEGORY channels by setting the parent_id field on any children + // to the category's id field. Category channels must be listed before any + // children. Channels []discord.Channel `json:"channels,omitempty"` + + // AFKChannelID is the id for the afk channel. + AFKChannelID discord.Snowflake `json:"afk_channel_id,omitempty"` + // AFKTimeout is the afk timeout in seconds. + AFKTimeout option.Seconds `json:"afk_timeout,omitempty"` + + // SystemChannelID is the id of the channel where guild notices such as + // welcome messages and boost events are posted. + SystemChannelID discord.Snowflake `json:"system_channel_id,omitempty"` } +// CreateGuild creates a new guild. Returns a guild object on success. +// Fires a Guild Create Gateway event. +// +// This endpoint can be used only by bots in less than 10 guilds. func (c *Client) CreateGuild(data CreateGuildData) (*discord.Guild, error) { var g *discord.Guild return g, c.RequestJSON(&g, "POST", Endpoint+"guilds", httputil.WithJSONBody(data)) } +// Guild returns the guild object for the given id. +// ApproximateMembers and ApproximatePresences will not be set. func (c *Client) Guild(id discord.Snowflake) (*discord.Guild, error) { var g *discord.Guild return g, c.RequestJSON(&g, "GET", EndpointGuilds+id.String()) } -// GuildWithCount will also return ApproximateMembers and ApproximatePresences -// for the guild. +// GuildWithCount returns the guild object for the given id. +// This will also set the ApproximateMembers and ApproximatePresences fields +// of the guild struct. func (c *Client) GuildWithCount(id discord.Snowflake) (*discord.Guild, error) { var g *discord.Guild - return g, c.RequestJSON( &g, "GET", EndpointGuilds+id.String(), @@ -57,15 +96,19 @@ func (c *Client) GuildWithCount(id discord.Snowflake) (*discord.Guild, error) { // Guilds returns all guilds, automatically paginating. Be careful, as this // method may abuse the API by requesting thousands or millions of guilds. For -// lower-level access, usee GuildsRange. Guilds returned have some fields +// lower-level access, use GuildsRange. Guilds returned have some fields // filled only (ID, Name, Icon, Owner, Permissions). +// +// Max can be 0, in which case the function will try and fetch all guilds. func (c *Client) Guilds(max uint) ([]discord.Guild, error) { var guilds []discord.Guild var after discord.Snowflake = 0 const hardLimit int = 100 - for fetch := uint(hardLimit); max > 0; fetch = uint(hardLimit) { + unlimited := max == 0 + + for fetch := uint(hardLimit); max > 0 || unlimited; fetch = uint(hardLimit) { if max > 0 { if fetch > max { fetch = max @@ -89,23 +132,27 @@ func (c *Client) Guilds(max uint) ([]discord.Guild, error) { return guilds, nil } -// GuildsBefore fetches guilds. Check GuildsRange. +// GuildsBefore fetches guilds before the specified ID. Check GuildsRange. func (c *Client) GuildsBefore(before discord.Snowflake, limit uint) ([]discord.Guild, error) { return c.GuildsRange(before, 0, limit) } -// GuildsAfter fetches guilds. Check GuildsRange. +// GuildsAfter fetches guilds after the specified ID. Check GuildsRange. func (c *Client) GuildsAfter(after discord.Snowflake, limit uint) ([]discord.Guild, error) { return c.GuildsRange(0, after, limit) } -// GuildsRange fetches guilds. The limit is 1-100. +// GuildsRange returns a list of partial guild objects the current user is a +// member of. Requires the guilds OAuth2 scope. +// +// This endpoint returns 100 guilds by default, which is the maximum number +// of guilds a non-bot user can join. Therefore, pagination is not needed +// for integrations that need to get a list of the users' guilds. func (c *Client) GuildsRange(before, after discord.Snowflake, limit uint) ([]discord.Guild, error) { - if limit == 0 { + switch { + case limit == 0: limit = 100 - } - - if limit > 100 { + case limit > 100: limit = 100 } @@ -128,36 +175,75 @@ func (c *Client) GuildsRange(before, after discord.Snowflake, limit uint) ([]dis ) } +// LeaveGuild leaves a guild. func (c *Client) LeaveGuild(id discord.Snowflake) error { return c.FastRequest("DELETE", EndpointMe+"/guilds/"+id.String()) } // https://discordapp.com/developers/docs/resources/guild#modify-guild-json-params type ModifyGuildData struct { - Name string `json:"name,omitempty"` - Region option.String `json:"region,omitempty"` + // Name is the guild's name. + Name string `json:"name,omitempty"` + // Region is the guild's voice region id. + Region option.NullableString `json:"region,omitempty"` - // package d is just package discord - Verification *discord.Verification `json:"verification_level,omitempty"` // nullable - Notification *discord.Notification `json:"default_message_notifications,omitempty"` // nullable - ExplicitFilter *discord.ExplicitFilter `json:"explicit_content_filter,omitempty"` // nullable + // Verification is the verification level. + // + // This field is nullable. + Verification *discord.Verification `json:"verification_level,omitempty"` + // Notification is the default message notification level. + // + // This field is nullable. + Notification *discord.Notification `json:"default_message_notifications,omitempty"` + // ExplicitFilter is the explicit content filter level. + // + // This field is nullable. + ExplicitFilter *discord.ExplicitFilter `json:"explicit_content_filter,omitempty"` + // AFKChannelID is the id for the afk channel. + // + // This field is nullable. AFKChannelID discord.Snowflake `json:"afk_channel_id,string,omitempty"` - AFKTimeout option.Seconds `json:"afk_timeout,omitempty"` - - OwnerID discord.Snowflake `json:"owner_id,omitempty"` - - Icon *Image `json:"icon,omitempty"` + // AFKTimeout is the afk timeout in seconds. + AFKTimeout option.Seconds `json:"afk_timeout,omitempty"` + // Icon is the base64 1024x1024 png/jpeg/gif image for the guild icon + // (can be animated gif when the server has the ANIMATED_ICON feature). + Icon *Image `json:"icon,omitempty"` + // Splash is the base64 16:9 png/jpeg image for the guild splash + // (when the server has the INVITE_SPLASH feature). Splash *Image `json:"splash,omitempty"` + // Banner is the base64 16:9 png/jpeg image for the guild banner (when the + // server has BANNER feature). Banner *Image `json:"banner,omitempty"` - SystemChannelID discord.Snowflake `json:"system_channel_id,omitempty"` - RulesChannelID discord.Snowflake `json:"rules_channel_id,omitempty"` + // OwnerID is the user id to transfer guild ownership to (must be owner). + OwnerID discord.Snowflake `json:"owner_id,omitempty"` + + // SystemChannelID is the id of the channel where guild notices such as + // welcome messages and boost events are posted. + // + // This field is nullable. + SystemChannelID discord.Snowflake `json:"system_channel_id,omitempty"` + // RulesChannelID is the id of the channel where "PUBLIC" guilds display + // rules and/or guidelines. + // + // This field is nullable. + RulesChannelID discord.Snowflake `json:"rules_channel_id,omitempty"` + // PublicUpdatesChannelID is the id of the channel where admins and + // moderators of "PUBLIC" guilds receive notices from Discord. + // + // This field is nullable. PublicUpdatesChannelID discord.Snowflake `json:"public_updates_channel_id,omitempty"` - PreferredLocale option.String `json:"preferred_locale,omitempty"` + // PreferredLocale is the preferred locale of a "PUBLIC" guild used in + // server discovery and notices from Discord. + // + // This defaults to "en-US". + PreferredLocale option.NullableString `json:"preferred_locale,omitempty"` } +// ModifyGuild modifies a guild's settings. Requires the MANAGE_GUILD permission. +// Fires a Guild Update Gateway event. func (c *Client) ModifyGuild(id discord.Snowflake, data ModifyGuildData) (*discord.Guild, error) { var g *discord.Guild return g, c.RequestJSON( @@ -167,6 +253,9 @@ func (c *Client) ModifyGuild(id discord.Snowflake, data ModifyGuildData) (*disco ) } +// DeleteGuild deletes a guild permanently. The User must be owner. +// +// Fires a Guild Delete Gateway event. func (c *Client) DeleteGuild(id discord.Snowflake) error { return c.FastRequest("DELETE", EndpointGuilds+id.String()) } @@ -178,21 +267,22 @@ func (c *Client) VoiceRegionsGuild(guildID discord.Snowflake) ([]discord.VoiceRe return vrs, c.RequestJSON(&vrs, "GET", EndpointGuilds+guildID.String()+"/regions") } -// AuditLogData contains query parameters used for AuditLog. All fields are -// optional. +// https://discord.com/developers/docs/resources/audit-log#get-guild-audit-log-query-string-parameters type AuditLogData struct { - // Filter the log for actions made by a user + // UserID filters the log for actions made by a user. UserID discord.Snowflake `schema:"user_id,omitempty"` - // The type of audit log event + // ActionType is the type of audit log event. ActionType discord.AuditLogEvent `schema:"action_type,omitempty"` - // Filter the log before a certain entry ID + // Before filters the log before a certain entry ID. Before discord.Snowflake `schema:"before,omitempty"` - // How many entries are returned (default 50, minimum 1, maximum 100) + // Limit limits how many entries are returned (default 50, minimum 1, + // maximum 100). Limit uint `schema:"limit"` } -// AuditLog returns an audit log object for the guild. Requires the -// VIEW_AUDIT_LOG permission. +// AuditLog returns an audit log object for the guild. +// +// Requires the VIEW_AUDIT_LOG permission. func (c *Client) AuditLog(guildID discord.Snowflake, data AuditLogData) (*discord.AuditLog, error) { switch { case data.Limit == 0: @@ -210,16 +300,21 @@ func (c *Client) AuditLog(guildID discord.Snowflake, data AuditLogData) (*discor ) } -// Integrations requires MANAGE_GUILD. +// Integrations returns a list of integration objects for the guild. +// +// Requires the MANAGE_GUILD permission. func (c *Client) Integrations(guildID discord.Snowflake) ([]discord.Integration, error) { var ints []discord.Integration return ints, c.RequestJSON(&ints, "GET", EndpointGuilds+guildID.String()+"/integrations") } -// AttachIntegration requires MANAGE_GUILD. -func (c *Client) AttachIntegration( - guildID, integrationID discord.Snowflake, - integrationType discord.Service) error { +// AttachIntegration attaches an integration object from the current user to +// the guild. +// +// Requires the MANAGE_GUILD permission. +// Fires a Guild Integrations Update Gateway event. +func (c *Client) AttachIntegration(guildID, + integrationID discord.Snowflake, integrationType discord.Service) error { var param struct { Type discord.Service `json:"type"` @@ -235,60 +330,114 @@ func (c *Client) AttachIntegration( // https://discord.com/developers/docs/resources/guild#modify-guild-integration-json-params type ModifyIntegrationData struct { - ExpireBehavior *discord.ExpireBehavior `json:"expire_behavior"` - ExpireGracePeriod option.Int `json:"expire_grace_period"` - EnableEmoticons option.Bool `json:"enable_emoticons"` // limited to twitch + // ExpireBehavior is the behavior when an integration subscription lapses + // (see the integration expire behaviors documentation). + ExpireBehavior *discord.ExpireBehavior `json:"expire_behavior,omitempty"` + // ExpireGracePeriod is the period (in days) where the integration will + // ignore lapsed subscriptions. + ExpireGracePeriod option.NullableInt `json:"expire_grace_period,omitempty"` + // EnableEmoticons specifies whether emoticons should be synced for this + // integration (twitch only currently). + EnableEmoticons option.NullableBool `json:"enable_emoticons,omitempty"` } -// ModifyIntegration requires MANAGE_GUILD. -func (c *Client) ModifyIntegration(guildID, integrationID discord.Snowflake, data ModifyIntegrationData) error { +// ModifyIntegration modifies the behavior and settings of an integration +// object for the guild. +// +// Requires the MANAGE_GUILD permission. +// Fires a Guild Integrations Update Gateway event. +func (c *Client) ModifyIntegration( + guildID, integrationID discord.Snowflake, data ModifyIntegrationData) error { return c.FastRequest( - "PATCH", EndpointGuilds+guildID.String()+"/integrations/"+integrationID.String(), + "PATCH", + EndpointGuilds+guildID.String()+"/integrations/"+integrationID.String(), httputil.WithJSONBody(data), ) } +// Sync an integration. Requires the MANAGE_GUILD permission. func (c *Client) SyncIntegration(guildID, integrationID discord.Snowflake) error { - return c.FastRequest("POST", EndpointGuilds+guildID.String()+ - "/integrations/"+integrationID.String()+"/sync") + return c.FastRequest( + "POST", + EndpointGuilds+guildID.String()+"/integrations/"+integrationID.String()+"/sync", + ) } +// GuildEmbed returns the guild embed object. +// +// Requires the MANAGE_GUILD permission. func (c *Client) GuildEmbed(guildID discord.Snowflake) (*discord.GuildEmbed, error) { var ge *discord.GuildEmbed return ge, c.RequestJSON(&ge, "GET", EndpointGuilds+guildID.String()+"/embed") } +// https://discord.com/developers/docs/resources/guild#guild-embed-object-guild-embed-structure +type ModifyGuildEmbedData struct { + Enabled option.Bool `json:"enabled,omitempty"` + ChannelID discord.Snowflake `json:"channel_id,omitempty"` +} + // ModifyGuildEmbed modifies the guild embed and updates the passed in // GuildEmbed data. // // This method should be used with care: if you still want the embed enabled, // you need to set the Enabled boolean, even if it's already enabled. If you // don't, JSON will default it to false. -func (c *Client) ModifyGuildEmbed(guildID discord.Snowflake, data *discord.GuildEmbed) error { +func (c *Client) ModifyGuildEmbed(guildID discord.Snowflake, data discord.GuildEmbed) error { return c.RequestJSON(&data, "PATCH", EndpointGuilds+guildID.String()+"/embed") } -// GuildVanityURL returns *Invite, but only Code and Uses are filled. Requires -// MANAGE_GUILD. +// GuildVanityURL returns *Invite for guilds that have that feature enabled, +// but only Code and Uses are filled. Code will be "" if a vanity url for the +// guild is not set. +// +// Requires MANAGE_GUILD. func (c *Client) GuildVanityURL(guildID discord.Snowflake) (*discord.Invite, error) { var inv *discord.Invite return inv, c.RequestJSON(&inv, "GET", EndpointGuilds+guildID.String()+"/vanity-url") } +// https://discord.com/developers/docs/resources/guild#get-guild-widget-image-widget-style-options type GuildImageStyle string const ( - GuildShield GuildImageStyle = "shield" + // GuildShield is a shield style widget with Discord icon and guild members + // online count. + // + // Example: https://discordapp.com/api/guilds/81384788765712384/widget.png?style=shield + GuildShield GuildImageStyle = "shield" + // GuildBanner1 is a large image with guild icon, name and online count. + // "POWERED BY DISCORD" as the footer of the widget. + // + // Example: https://discordapp.com/api/guilds/81384788765712384/widget.png?style=banner1 GuildBanner1 GuildImageStyle = "banner1" + // GuildBanner2 is a smaller widget style with guild icon, name and online + // count. Split on the right with Discord logo. + // + // Example: https://discordapp.com/api/guilds/81384788765712384/widget.png?style=banner2 GuildBanner2 GuildImageStyle = "banner2" + // GuildBanner3 is a large image with guild icon, name and online count. In + // the footer, Discord logo on the left and "Chat Now" on the right. + // + // Example: https://discordapp.com/api/guilds/81384788765712384/widget.png?style=banner3 GuildBanner3 GuildImageStyle = "banner3" + // GuildBanner4 is a large Discord logo at the top of the widget. + // Guild icon, name and online count in the middle portion of the widget + // and a "JOIN MY SERVER" button at the bottom. + // + // Example: https://discordapp.com/api/guilds/81384788765712384/widget.png?style=banner4 GuildBanner4 GuildImageStyle = "banner4" ) +// GuildImageURL returns a link to the PNG image widget for the guild. +// +// Requires no permissions or authentication. func (c *Client) GuildImageURL(guildID discord.Snowflake, img GuildImageStyle) string { return EndpointGuilds + guildID.String() + "/widget.png?style=" + string(img) } +// GuildImage returns a PNG image widget for the guild. Requires no permissions +// or authentication. func (c *Client) GuildImage(guildID discord.Snowflake, img GuildImageStyle) (io.ReadCloser, error) { r, err := c.Request("GET", c.GuildImageURL(guildID, img)) if err != nil { diff --git a/api/invite.go b/api/invite.go index 93cd5c7..cf7c536 100644 --- a/api/invite.go +++ b/api/invite.go @@ -3,10 +3,12 @@ package api import ( "github.com/diamondburned/arikawa/discord" "github.com/diamondburned/arikawa/utils/httputil" + "github.com/diamondburned/arikawa/utils/json/option" ) var EndpointInvites = Endpoint + "invites/" +// Invite returns an invite object for the given code. func (c *Client) Invite(code string) (*discord.Invite, error) { var params struct { WithCounts bool `schema:"with_counts,omitempty"` @@ -23,53 +25,66 @@ func (c *Client) Invite(code string) (*discord.Invite, error) { ) } -// ChannelInvites is only for guild channels. GuildInvites is for guilds. +// ChannelInvites returns a list of invite objects (with invite metadata) for +// the channel. Only usable for guild channels. +// +// Requires the MANAGE_CHANNELS permission. func (c *Client) ChannelInvites(channelID discord.Snowflake) ([]discord.Invite, error) { var invs []discord.Invite return invs, c.RequestJSON(&invs, "GET", EndpointChannels+channelID.String()+"/invites") } -// GuildInvites is for guilds. +// GuildInvites returns a list of invite objects (with invite metadata) for the +// guild. +// +// Requires the MANAGE_GUILD permission. func (c *Client) GuildInvites(guildID discord.Snowflake) ([]discord.Invite, error) { var invs []discord.Invite return invs, c.RequestJSON(&invs, "GET", EndpointGuilds+guildID.String()+"/invites") } -// CreateInvite is only for guild channels. This endpoint requires -// CREATE_INSTANT_INVITE. +// https://discord.com/developers/docs/resources/channel#create-channel-invite-json-params +type CreateInviteData struct { + // MaxAge is the duration of invite in seconds before expiry, or 0 for + // never. + // + // Default: 86400 (24 hours) + MaxAge option.Uint `json:"max_age,omitempty"` + // MaxUses is the max number of uses or 0 for unlimited. + // + // Default: 0 + MaxUses uint `json:"max_uses,omitempty"` + // Temporary specifies whether this invite only grants temporary membership. + // + // Default: false + Temporary bool `json:"temporary,omitempty"` + // Unique has the following behavior: if true, don't try to reuse a similar + // invite (useful for creating many unique one time use invites). + // + // Default: false + Unique bool `json:"unique,omitempty"` +} + +// CreateInvite creates a new invite object for the channel. Only usable for +// guild channels. // -// MaxAge is the duration before expiry, 0 for never. MaxUses is the maximum -// number of uses, 0 for unlimited. Temporary is whether this invite grants -// temporary membership. Unique, if true, tries not to reuse a similar invite, -// useful for creating unique one time use invites. +// Requires the CREATE_INSTANT_INVITE permission. func (c *Client) CreateInvite( - channelID discord.Snowflake, maxAge discord.Seconds, - maxUses uint, temp, unique bool) (*discord.Invite, error) { - - var param struct { - MaxAge int `json:"max_age"` - MaxUses uint `json:"max_uses"` - Temporary bool `json:"temporary"` - Unique bool `json:"unique"` - } - - param.MaxAge = int(maxAge) - param.MaxUses = maxUses - param.Temporary = temp - param.Unique = unique - + channelID discord.Snowflake, data CreateInviteData) (*discord.Invite, error) { var inv *discord.Invite return inv, c.RequestJSON( &inv, "POST", EndpointChannels+channelID.String()+"/invites", - httputil.WithSchema(c, param), + httputil.WithJSONBody(data), ) } -// DeleteInvite requires either MANAGE_CHANNELS on the target channel, or -// MANAGE_GUILD to remove any invite in the guild. +// DeleteInvite deletes a channel permission overwrite for a user or role in a +// channel. Only usable for guild channels. +// +// Requires the MANAGE_ROLES permission. func (c *Client) DeleteInvite(code string) (*discord.Invite, error) { var inv *discord.Invite return inv, c.RequestJSON(&inv, "DELETE", EndpointInvites+code) diff --git a/api/member.go b/api/member.go index 414a0b5..1c60c02 100644 --- a/api/member.go +++ b/api/member.go @@ -6,6 +6,7 @@ import ( "github.com/diamondburned/arikawa/utils/json/option" ) +// Member returns a guild member object for the specified user.. func (c *Client) Member(guildID, userID discord.Snowflake) (*discord.Member, error) { var m *discord.Member return m, c.RequestJSON(&m, "GET", @@ -13,17 +14,18 @@ func (c *Client) Member(guildID, userID discord.Snowflake) (*discord.Member, err } // Members returns members until it reaches max. This function automatically -// paginates, meaning the normal 1000 limit is handled internally. Max can be 0, -// in which the function will try and fetch everything. -func (c *Client) Members( - guildID discord.Snowflake, max uint) ([]discord.Member, error) { - +// paginates, meaning the normal 1000 limit is handled internally. +// +// Max can be 0, in which case the function will try and fetch all members. +func (c *Client) Members(guildID discord.Snowflake, max uint) ([]discord.Member, error) { var mems []discord.Member var after discord.Snowflake = 0 const hardLimit int = 1000 - for fetch := uint(hardLimit); max > 0; fetch = uint(hardLimit) { + unlimited := max == 0 + + for fetch := uint(hardLimit); max > 0 || unlimited; fetch = uint(hardLimit) { if max > 0 { if fetch > max { fetch = max @@ -53,18 +55,16 @@ func (c *Client) Members( func (c *Client) MembersAfter( guildID, after discord.Snowflake, limit uint) ([]discord.Member, error) { - if limit == 0 { - limit = 1 - } - - if limit > 1000 { + switch { + case limit == 0: + limit = 0 + case limit > 1000: limit = 1000 } var param struct { After discord.Snowflake `schema:"after,omitempty"` - - Limit uint `schema:"limit"` + Limit uint `schema:"limit"` } param.Limit = limit @@ -78,45 +78,80 @@ func (c *Client) MembersAfter( ) } -// AnyMemberData, all fields are optional. -type AnyMemberData struct { +// 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"` - Mute option.Bool `json:"mute,omitempty"` - Deaf option.Bool `json:"deaf,omitempty"` - + // Roles is an array of role ids the member is assigned. + // + // Requires MANAGE_ROLES. Roles *[]discord.Snowflake `json:"roles,omitempty"` - - // Only for ModifyMember, requires MOVE_MEMBER - VoiceChannel discord.Snowflake `json:"channel_id,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 requires access(Token). +// 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, userID discord.Snowflake, token string, - data AnyMemberData) (*discord.Member, error) { - - // VoiceChannel doesn't belong here. - data.VoiceChannel = -1 - - var param struct { - Token string `json:"access_token"` - AnyMemberData - } - - param.Token = token - param.AnyMemberData = data - + guildID, userID discord.Snowflake, data AddMemberData) (*discord.Member, error) { var mem *discord.Member - return mem, c.RequestJSON( &mem, "PUT", EndpointGuilds+guildID.String()+"/members/"+userID.String(), - httputil.WithJSONBody(param), + httputil.WithJSONBody(data), ) } -func (c *Client) ModifyMember( - guildID, userID discord.Snowflake, data AnyMemberData) error { +// 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.Snowflake `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.Snowflake `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, userID discord.Snowflake, data ModifyMemberData) error { return c.FastRequest( "PATCH", @@ -126,7 +161,9 @@ func (c *Client) ModifyMember( } // PruneCount returns the number of members that would be removed in a prune -// operation. Requires KICK_MEMBERS. Days must be 1 or more, default 7. +// operation. Days must be 1 or more, default 7. +// +// Requires KICK_MEMBERS. func (c *Client) PruneCount(guildID discord.Snowflake, days uint) (uint, error) { if days == 0 { days = 7 @@ -149,8 +186,10 @@ func (c *Client) PruneCount(guildID discord.Snowflake, days uint) (uint, error) ) } -// Prune returns the number of members that is removed. Requires KICK_MEMBERS. -// Days must be 1 or more, default 7. +// Prune returns the number of members that is removed. Days must be 1 or more, +// default 7. +// +// Requires KICK_MEMBERS. func (c *Client) Prune(guildID discord.Snowflake, days uint) (uint, error) { if days == 0 { days = 7 @@ -175,47 +214,61 @@ func (c *Client) Prune(guildID discord.Snowflake, days uint) (uint, error) { ) } -// Kick requires KICK_MEMBERS. +// Kick removes a member from a guild. +// +// Requires KICK_MEMBERS permission. +// Fires a Guild Member Remove Gateway event. func (c *Client) Kick(guildID, userID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointGuilds+guildID.String()+"/members/"+userID.String()) } +// 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.Snowflake) ([]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, userID discord.Snowflake) (*discord.Ban, error) { var ban *discord.Ban return ban, c.RequestJSON(&ban, "GET", EndpointGuilds+guildID.String()+"/bans/"+userID.String()) } -// Ban requires the BAN_MEMBERS permission. Days is the days back for Discord -// to delete the user's message, maximum 7 days. -func (c *Client) Ban(guildID, userID discord.Snowflake, days uint, reason string) error { - if days > 7 { - days = 7 - } +// 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"` +} - var param struct { - DeleteDays uint `schema:"delete_message_days,omitempty"` - Reason 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, userID discord.Snowflake, data BanData) error { + if *data.DeleteDays > 7 { + *data.DeleteDays = 7 } - param.DeleteDays = days - param.Reason = reason - return c.FastRequest( "PUT", EndpointGuilds+guildID.String()+"/bans/"+userID.String(), - httputil.WithSchema(c, param), + httputil.WithSchema(c, data), ) } -// Unban requires BAN_MEMBERS. +// Unban removes the ban for a user. +// +// Requires the BAN_MEMBERS permissions. +// Fires a Guild Ban Remove Gateway event. func (c *Client) Unban(guildID, userID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointGuilds+guildID.String()+"/bans/"+userID.String()) } diff --git a/api/message.go b/api/message.go index fab0124..fcfa45f 100644 --- a/api/message.go +++ b/api/message.go @@ -3,18 +3,23 @@ package api import ( "github.com/diamondburned/arikawa/discord" "github.com/diamondburned/arikawa/utils/httputil" + "github.com/diamondburned/arikawa/utils/json/option" ) -// Messages gets all mesesages, automatically paginating. Use with care, as +// Messages gets all messages, automatically paginating. Use with care, as // this could get as many as hundred thousands of messages, making a lot of // queries. +// +// Max can be 0, in which case the function will try and fetch all messages. func (c *Client) Messages(channelID discord.Snowflake, max uint) ([]discord.Message, error) { var msgs []discord.Message var after discord.Snowflake = 0 const hardLimit int = 100 - for fetch := uint(hardLimit); max > 0; fetch = uint(hardLimit) { + unlimited := max == 0 + + for fetch := uint(hardLimit); max > 0 || unlimited; fetch = uint(hardLimit) { if max > 0 { if fetch > max { fetch = max @@ -40,24 +45,21 @@ func (c *Client) Messages(channelID discord.Snowflake, max uint) ([]discord.Mess // MessagesAround returns messages around the ID, with a limit of 1-100. func (c *Client) MessagesAround( - channelID, around discord.Snowflake, - limit uint) ([]discord.Message, error) { + channelID, around discord.Snowflake, limit uint) ([]discord.Message, error) { return c.messagesRange(channelID, 0, 0, around, limit) } // MessagesBefore returns messages before the ID, with a limit of 1-100. func (c *Client) MessagesBefore( - channelID, before discord.Snowflake, - limit uint) ([]discord.Message, error) { + channelID, before discord.Snowflake, limit uint) ([]discord.Message, error) { return c.messagesRange(channelID, before, 0, 0, limit) } // MessagesAfter returns messages after the ID, with a limit of 1-100. func (c *Client) MessagesAfter( - channelID, after discord.Snowflake, - limit uint) ([]discord.Message, error) { + channelID, after discord.Snowflake, limit uint) ([]discord.Message, error) { return c.messagesRange(channelID, 0, after, 0, limit) } @@ -94,15 +96,24 @@ func (c *Client) messagesRange( ) } +// Message returns a specific message in the channel. +// +// If operating on a guild channel, this endpoint requires the +// READ_MESSAGE_HISTORY permission to be present on the current user. func (c *Client) Message(channelID, messageID discord.Snowflake) (*discord.Message, error) { var msg *discord.Message return msg, c.RequestJSON(&msg, "GET", EndpointChannels+channelID.String()+"/messages/"+messageID.String()) } +// SendMessage posts a message to a guild text or DM channel. +// +// If operating on a guild channel, this endpoint requires the SEND_MESSAGES +// permission to be present on the current user. +// +// Fires a Message Create Gateway event. func (c *Client) SendMessage( - channelID discord.Snowflake, content string, - embed *discord.Embed) (*discord.Message, error) { + channelID discord.Snowflake, content string, embed *discord.Embed) (*discord.Message, error) { return c.SendMessageComplex(channelID, SendMessageData{ Content: content, @@ -110,39 +121,57 @@ func (c *Client) SendMessage( }) } +// https://discord.com/developers/docs/resources/channel#edit-message-json-params +type EditMessageData struct { + // Content is the new message contents (up to 2000 characters). + Content option.NullableString `json:"content,omitempty"` + // Embed contains embedded rich content. + Embed *discord.Embed `json:"embed,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + // Flags edits the flags of a message (only SUPPRESS_EMBEDS can currently + // be set/unset) + // + // This field is nullable. + Flags *discord.MessageFlags `json:"flags,omitempty"` +} + +// Edit a previously sent message. The fields Content, Embed, +// AllowedMentions and Flags can be edited by the original message author. +// Other users can only edit flags and only if they have the MANAGE_MESSAGES +// permission in the corresponding channel. When specifying flags, ensure to +// include all previously set flags/bits in addition to ones that you are +// modifying. Only flags documented in EditMessageData may be modified by users +// (unsupported flag changes are currently ignored without error). +// +// Fires a Message Update Gateway event. func (c *Client) EditMessage( - channelID, messageID discord.Snowflake, content string, - embed *discord.Embed, suppressEmbeds bool) (*discord.Message, error) { - - var param struct { - Content string `json:"content,omitempty"` - Embed *discord.Embed `json:"embed,omitempty"` - Flags discord.MessageFlags `json:"flags,omitempty"` - } - - param.Content = content - param.Embed = embed - if suppressEmbeds { - param.Flags = discord.SuppressEmbeds - } + channelID, messageID discord.Snowflake, data EditMessageData) (*discord.Message, error) { var msg *discord.Message return msg, c.RequestJSON( &msg, "PATCH", EndpointChannels+channelID.String()+"/messages/"+messageID.String(), - httputil.WithJSONBody(param), + httputil.WithJSONBody(data), ) } -// DeleteMessage deletes a message. Requires MANAGE_MESSAGES if the message is -// not made by yourself. +// DeleteMessage delete a message. If operating on a guild channel and trying +// to delete a message that was not sent by the current user, this endpoint +// requires the MANAGE_MESSAGES permission. func (c *Client) DeleteMessage(channelID, messageID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointChannels+channelID.String()+ "/messages/"+messageID.String()) } -// DeleteMessages only works for bots. It can't delete messages older than 2 -// weeks, and will fail if tried. This endpoint requires MANAGE_MESSAGES. +// DeleteMessages deletes multiple messages in a single request. This endpoint +// can only be used on guild channels and requires the MANAGE_MESSAGES +// permission. This endpoint only works for bots. +// +// This endpoint will not delete messages older than 2 weeks, and will fail if +// any message provided is older than that or if any duplicate message IDs are +// provided. +// +// Fires a Message Delete Bulk Gateway event. func (c *Client) DeleteMessages(channelID discord.Snowflake, messageIDs []discord.Snowflake) error { var param struct { Messages []discord.Snowflake `json:"messages"` diff --git a/api/message_reaction.go b/api/message_reaction.go index 81c3342..c51e4b9 100644 --- a/api/message_reaction.go +++ b/api/message_reaction.go @@ -5,26 +5,30 @@ import ( "github.com/diamondburned/arikawa/utils/httputil" ) -// React adds a reaction to the message. This requires READ_MESSAGE_HISTORY (and -// additionally ADD_REACTIONS) to react. -func (c *Client) React( - channelID, messageID discord.Snowflake, emoji EmojiAPI) error { - +// React creates a reaction for the message. +// +// This endpoint requires the READ_MESSAGE_HISTORY permission to be present on +// the current user. Additionally, if nobody else has reacted to the message +// using this emoji, this endpoint requires the 'ADD_REACTIONS' permission to +// be present on the current user. +func (c *Client) React(channelID, messageID discord.Snowflake, emoji EmojiAPI) error { var msgURL = EndpointChannels + channelID.String() + "/messages/" + messageID.String() + "/reactions/" + emoji + "/@me" return c.FastRequest("PUT", msgURL) } -// Unreact removes own's reaction from the message. +// Unreact removes a reaction the current user has made for the message. func (c *Client) Unreact(chID, msgID discord.Snowflake, emoji EmojiAPI) error { return c.DeleteUserReaction(chID, msgID, 0, emoji) } -// Reactions returns all reactions. It will paginate automatically. +// Reactions returns reactions up to the specified limit. It will paginate +// automatically. +// +// Max can be 0, in which case the function will try and fetch all reactions. func (c *Client) Reactions( - channelID, messageID discord.Snowflake, - max uint, emoji EmojiAPI) ([]discord.User, error) { + channelID, messageID discord.Snowflake, max uint, emoji EmojiAPI) ([]discord.User, error) { var users []discord.User var after discord.Snowflake = 0 @@ -55,7 +59,7 @@ func (c *Client) Reactions( return users, nil } -// Refer to ReactionsRange. +// ReactionsBefore gets all reactions before the passed user ID. func (c *Client) ReactionsBefore( channelID, messageID, before discord.Snowflake, limit uint, emoji EmojiAPI) ([]discord.User, error) { @@ -77,11 +81,10 @@ func (c *Client) ReactionsRange( channelID, messageID, before, after discord.Snowflake, limit uint, emoji EmojiAPI) ([]discord.User, error) { - if limit == 0 { + switch { + case limit == 0: limit = 25 - } - - if limit > 100 { + case limit > 100: limit = 100 } @@ -105,31 +108,42 @@ func (c *Client) ReactionsRange( ) } -// DeleteReaction requires MANAGE_MESSAGES if not @me. +// DeleteReaction deletes another user's reaction. +// +// This endpoint requires the MANAGE_MESSAGES permission to be present on the +// current user. func (c *Client) DeleteUserReaction( - chID, msgID, userID discord.Snowflake, emoji EmojiAPI) error { + channelID, messageID, userID discord.Snowflake, emoji EmojiAPI) error { var user = "@me" if userID > 0 { user = userID.String() } - return c.FastRequest("DELETE", EndpointChannels+chID.String()+ - "/messages/"+msgID.String()+ + return c.FastRequest("DELETE", EndpointChannels+channelID.String()+ + "/messages/"+messageID.String()+ "/reactions/"+emoji+"/"+user) } -// DeleteReactions equires MANAGE_MESSAGE. +// DeleteReactions deletes all the reactions for a given emoji on a message. +// +// This endpoint requires the MANAGE_MESSAGES permission to be present on the +// current user. +// Fires a Message Reaction Remove Emoji Gateway event. func (c *Client) DeleteReactions( - chID, msgID discord.Snowflake, emoji EmojiAPI) error { + channelId, messageID discord.Snowflake, emoji EmojiAPI) error { - return c.FastRequest("DELETE", EndpointChannels+chID.String()+ - "/messages/"+msgID.String()+ + return c.FastRequest("DELETE", EndpointChannels+channelId.String()+ + "/messages/"+messageID.String()+ "/reactions/"+emoji) } -// DeleteAllReactions equires MANAGE_MESSAGE. -func (c *Client) DeleteAllReactions(chID, msgID discord.Snowflake) error { - return c.FastRequest("DELETE", EndpointChannels+chID.String()+ - "/messages/"+msgID.String()+"/reactions/") +// DeleteAllReactions deletes all reactions on a message. +// +// This endpoint requires the MANAGE_MESSAGES permission to be present on the +// current user. +// Fires a Message Reaction Remove All Gateway event. +func (c *Client) DeleteAllReactions(channelID, messageID discord.Snowflake) error { + return c.FastRequest("DELETE", EndpointChannels+channelID.String()+ + "/messages/"+messageID.String()+"/reactions/") } diff --git a/api/role.go b/api/role.go index b2c0955..c23fbf0 100644 --- a/api/role.go +++ b/api/role.go @@ -6,34 +6,64 @@ import ( "github.com/diamondburned/arikawa/utils/json/option" ) +// Adds a role to a guild member. +// +// Requires the MANAGE_ROLES permission. func (c *Client) AddRole(guildID, userID, roleID discord.Snowflake) error { return c.FastRequest("PUT", EndpointGuilds+guildID.String()+ "/members/"+userID.String()+ "/roles/"+roleID.String()) } +// RemoveRole removes a role from a guild member. +// +// Requires the MANAGE_ROLES permission. +// Fires a Guild Member Update Gateway event. func (c *Client) RemoveRole(guildID, userID, roleID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointGuilds+guildID.String()+ "/members/"+userID.String()+ "/roles/"+roleID.String()) } +// Roles returns a list of role objects for the guild. func (c *Client) Roles(guildID discord.Snowflake) ([]discord.Role, error) { var roles []discord.Role return roles, c.RequestJSON(&roles, "GET", EndpointGuilds+guildID.String()+"/roles") } +// https://discord.com/developers/docs/resources/guild#create-guild-role-json-params type CreateRoleData struct { - Name string `json:"name,omitempty"` // "new role" - Color discord.Color `json:"color,omitempty"` // 0 - Hoist bool `json:"hoist,omitempty"` // false (show role separately) - - Mentionable bool `json:"mentionable,omitempty"` // false - Permissions discord.Permissions `json:"permissions,omitempty"` // @everyone + // Name is the name of the role. + // + // Default: "new role" + Name string `json:"name,omitempty"` + // Permissions is the bitwise value of the enabled/disabled permissions. + // + // Default: @everyone permissions in guild + Permissions discord.Permissions `json:"permissions,omitempty"` + // Color is the RGB color value of the role. + // + // Default: 0 + Color discord.Color `json:"color,omitempty"` + // Hoist specifies whether the role should be displayed separately in the + // sidebar. + // + // Default: false + Hoist bool `json:"hoist,omitempty"` + // Mentionable specifies whether the role should be mentionable. + // + // Default: false + Mentionable bool `json:"mentionable,omitempty"` } -func (c *Client) CreateRole(guildID discord.Snowflake, data CreateRoleData) (*discord.Role, error) { +// CreateRole creates a new role for the guild. +// +// Requires the MANAGE_ROLES permission. +// Fires a Guild Role Create Gateway event. +func (c *Client) CreateRole( + guildID discord.Snowflake, data CreateRoleData) (*discord.Role, error) { + var role *discord.Role return role, c.RequestJSON( &role, "POST", @@ -42,34 +72,45 @@ func (c *Client) CreateRole(guildID discord.Snowflake, data CreateRoleData) (*di ) } -func (c *Client) MoveRole( - guildID, roleID discord.Snowflake, position int) ([]discord.Role, error) { - - var param struct { - ID discord.Snowflake `json:"id"` - Pos int `json:"position"` - } - - param.ID = roleID - param.Pos = position +// https://discord.com/developers/docs/resources/guild#modify-guild-role-positions-json-params +type MoveRoleData struct { + // ID is the id of the role. + ID discord.Snowflake `json:"id"` + // Position is the sorting position of the role. + Position option.NullableInt `json:"position,omitempty"` +} +// MoveRole modifies the positions of a set of role objects for the guild. +// +// Requires the MANAGE_ROLES permission. +// Fires multiple Guild Role Update Gateway events. +func (c *Client) MoveRole(guildID discord.Snowflake, data []MoveRoleData) ([]discord.Role, error) { var roles []discord.Role return roles, c.RequestJSON( &roles, "PATCH", EndpointGuilds+guildID.String()+"/roles", - httputil.WithJSONBody(param), + httputil.WithJSONBody(data), ) } +// https://discord.com/developers/docs/resources/guild#modify-guild-role-json-params type ModifyRoleData struct { - Name string `json:"name,omitempty"` // "new role" - Color option.Color `json:"color,omitempty"` // 0 - Hoist option.Bool `json:"hoist,omitempty"` // false (show role separately) - - Mentionable option.Bool `json:"mentionable,omitempty"` // false - Permissions discord.Permissions `json:"permissions,omitempty"` // @everyone + // Name is the name of the role. + Name option.NullableString `json:"name,omitempty"` + // Permissions is the bitwise value of the enabled/disabled permissions. + Permissions *discord.Permissions `json:"permissions,omitempty"` + // Permissions is the bitwise value of the enabled/disabled permissions. + Color option.NullableColor `json:"color,omitempty"` + // Hoist specifies whether the role should be displayed separately in the + // sidebar. + Hoist option.NullableBool `json:"hoist,omitempty"` + // Mentionable specifies whether the role should be mentionable. + Mentionable option.NullableBool `json:"mentionable,omitempty"` } +// ModifyRole modifies a guild role. +// +// Requires the MANAGE_ROLES permission. func (c *Client) ModifyRole( guildID, roleID discord.Snowflake, data ModifyRoleData) (*discord.Role, error) { @@ -82,6 +123,9 @@ func (c *Client) ModifyRole( ) } +// DeleteRole deletes a guild role. +// +// Requires the MANAGE_ROLES permission. func (c *Client) DeleteRole(guildID, roleID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointGuilds+guildID.String()+"/roles/"+roleID.String()) diff --git a/api/send.go b/api/send.go index b3cb74d..bf99b34 100644 --- a/api/send.go +++ b/api/send.go @@ -38,9 +38,12 @@ var quoteEscaper = strings.NewReplacer(`\`, `\\`, `"`, `\"`) // Discord parse it completely, meaning they would be mutually exclusive with // whitelist slices, Roles and Users. type AllowedMentions struct { + // Parse is an array of allowed mention types to parse from the content. Parse []AllowedMentionType `json:"parse"` - Roles []discord.Snowflake `json:"roles,omitempty"` // max 100 - Users []discord.Snowflake `json:"users,omitempty"` // max 100 + // Roles is an array of role_ids to mention (Max size of 100). + Roles []discord.Snowflake `json:"roles,omitempty"` + // Users is an array of user_ids to mention (Max size of 100). + Users []discord.Snowflake `json:"users,omitempty"` } // AllowedMentionType is a constant that tells Discord what is allowed to parse @@ -95,15 +98,19 @@ type SendMessageFile struct { // SendMessageData is the full structure to send a new message to Discord with. type SendMessageData struct { - // Either of these fields must not be empty. + // Content are the message contents (up to 2000 characters). Content string `json:"content,omitempty"` - Nonce string `json:"nonce,omitempty"` + // Nonce is a nonce that can be used for optimistic message sending. + Nonce string `json:"nonce,omitempty"` - TTS bool `json:"tts,omitempty"` + // TTS is true if this is a TTS message. + TTS bool `json:"tts,omitempty"` + // Embed is embedded rich content. Embed *discord.Embed `json:"embed,omitempty"` Files []SendMessageFile `json:"-"` + // AllowedMentions are the allowed mentions for a message. AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` } @@ -111,6 +118,25 @@ func (data *SendMessageData) WriteMultipart(body *multipart.Writer) error { return writeMultipart(body, data, data.Files) } +// SendMessageComplex posts a message to a guild text or DM channel. If +// operating on a guild channel, this endpoint requires the SEND_MESSAGES +// permission to be present on the current user. If the tts field is set to +// true, the SEND_TTS_MESSAGES permission is required for the message to be +// spoken. Returns a message object. Fires a Message Create Gateway event. +// +// The maximum request size when sending a message is 8MB. +// +// This endpoint supports requests with Content-Types of both application/json +// and multipart/form-data. You must however use multipart/form-data when +// uploading files. Note that when sending multipart/form-data requests the +// embed field cannot be used, however you can pass a JSON encoded body as form +// value for payload_json, where additional request parameters such as embed +// can be set. +// +// Note that when sending application/json you must send at least one of +// content or embed, and when sending multipart/form-data, you must send at +// least one of content, embed or file. For a file attachment, the +// Content-Disposition subpart header MUST contain a filename parameter. func (c *Client) SendMessageComplex( channelID discord.Snowflake, data SendMessageData) (*discord.Message, error) { @@ -154,20 +180,27 @@ func (c *Client) SendMessageComplex( } type ExecuteWebhookData struct { - // Either of these fields must not be empty. + // Content are the message contents (up to 2000 characters). + // + // Required: one of content, file, embeds Content string `json:"content,omitempty"` - Nonce string `json:"nonce,omitempty"` - TTS bool `json:"tts,omitempty"` + // Username overrides the default username of the webhook + Username string `json:"username,omitempty"` + // AvatarURL overrides the default avatar of the webhook. + AvatarURL discord.URL `json:"avatar_url,omitempty"` + + // TTS is true if this is a TTS message. + TTS bool `json:"tts,omitempty"` + // Embeds contains embedded rich content. + // + // Required: one of content, file, embeds Embeds []discord.Embed `json:"embeds,omitempty"` Files []SendMessageFile `json:"-"` + // AllowedMentions are the allowed mentions for the message. AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - - // Optional fields specific to Webhooks. - Username string `json:"username,omitempty"` - AvatarURL discord.URL `json:"avatar_url,omitempty"` } func (data *ExecuteWebhookData) WriteMultipart(body *multipart.Writer) error { diff --git a/api/user.go b/api/user.go index ef8eebb..89f4848 100644 --- a/api/user.go +++ b/api/user.go @@ -3,6 +3,7 @@ package api import ( "github.com/diamondburned/arikawa/discord" "github.com/diamondburned/arikawa/utils/httputil" + "github.com/diamondburned/arikawa/utils/json/option" ) var ( @@ -10,40 +11,51 @@ var ( EndpointMe = EndpointUsers + "@me" ) +// User returns a user object for a given user ID. func (c *Client) User(userID discord.Snowflake) (*discord.User, error) { var u *discord.User return u, c.RequestJSON(&u, "GET", EndpointUsers+userID.String()) } +// Me returns the user object of the requester's account. For OAuth2, this +// requires the identify scope, which will return the object without an email, +// and optionally the email scope, which returns the object with an email. func (c *Client) Me() (*discord.User, error) { var me *discord.User return me, c.RequestJSON(&me, "GET", EndpointMe) } +// https://discord.com/developers/docs/resources/user#modify-current-user-json-params type ModifySelfData struct { - Username string `json:"username,omitempty"` - Avatar *Image `json:"image,omitempty"` + // Username is the user's username, if changed may cause the user's + // discriminator to be randomized. + Username option.String `json:"username,omitempty"` + // Avatar modifies the user's avatar. + Avatar *Image `json:"image,omitempty"` } +// ModifyMe modifies the requester's user account settings. func (c *Client) ModifyMe(data ModifySelfData) (*discord.User, error) { var u *discord.User - return u, c.RequestJSON(&u, "PATCH", EndpointMe) + return u, c.RequestJSON(&u, "PATCH", EndpointMe, httputil.WithJSONBody(data)) } +// PrivateChannels returns a list of DM channel objects. For bots, this is no +// longer a supported method of getting recent DMs, and will return an empty +// array. func (c *Client) PrivateChannels() ([]discord.Channel, error) { var dms []discord.Channel return dms, c.RequestJSON(&dms, "GET", EndpointMe+"/channels") } -func (c *Client) CreatePrivateChannel( - recipient discord.Snowflake) (*discord.Channel, error) { - +// CreatePrivateChannel creates a new DM channel with a user. +func (c *Client) CreatePrivateChannel(recipientID discord.Snowflake) (*discord.Channel, error) { var param struct { RecipientID discord.Snowflake `json:"recipient_id"` } - param.RecipientID = recipient + param.RecipientID = recipientID var dm *discord.Channel return dm, c.RequestJSON(&dm, "POST", EndpointMe+"/channels", diff --git a/api/webhook.go b/api/webhook.go index c44b25c..22a7dda 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -3,12 +3,24 @@ package api import ( "github.com/diamondburned/arikawa/discord" "github.com/diamondburned/arikawa/utils/httputil" + "github.com/diamondburned/arikawa/utils/json/option" ) var EndpointWebhooks = Endpoint + "webhooks/" -// CreateWebhook creates a new webhook; avatar hash is optional. Requires -// MANAGE_WEBHOOKS. +// https://discord.com/developers/docs/resources/webhook#create-webhook-json-params +type CreateWebhookData struct { + // Name is the name of the webhook (1-80 characters). + Name string `json:"name"` + // Avatar is the image for the default webhook avatar. + Avatar *Image `json:"avatar"` +} + +// CreateWebhook creates a new webhook. +// +// Webhooks cannot be named "clyde". +// +// Requires the MANAGE_WEBHOOKS permission. func (c *Client) CreateWebhook( channelID discord.Snowflake, name string, avatar discord.Hash) (*discord.Webhook, error) { @@ -29,17 +41,22 @@ func (c *Client) CreateWebhook( ) } -// Webhooks requires MANAGE_WEBHOOKS. +// Webhooks returns the guild webhooks. +// +// Requires the MANAGE_WEBHOOKS permission. func (c *Client) Webhooks(guildID discord.Snowflake) ([]discord.Webhook, error) { var ws []discord.Webhook return ws, c.RequestJSON(&ws, "GET", EndpointGuilds+guildID.String()+"/webhooks") } +// Webhook returns the webhook with the given id. func (c *Client) Webhook(webhookID discord.Snowflake) (*discord.Webhook, error) { var w *discord.Webhook return w, c.RequestJSON(&w, "GET", EndpointWebhooks+webhookID.String()) } +// WebhookWithToken is the same as above, except this call does not require +// authentication and returns no user in the webhook object. func (c *Client) WebhookWithToken( webhookID discord.Snowflake, token string) (*discord.Webhook, error) { @@ -47,32 +64,52 @@ func (c *Client) WebhookWithToken( return w, c.RequestJSON(&w, "GET", EndpointWebhooks+webhookID.String()+"/"+token) } +// https://discord.com/developers/docs/resources/webhook#modify-webhook-json-params type ModifyWebhookData struct { - Name string `json:"name,omitempty"` - Avatar discord.Hash `json:"avatar,omitempty"` // TODO: clear avatar how? + // Name is the default name of the webhook. + Name option.String `json:"name,omitempty"` + // Avatar is the image for the default webhook avatar. + Avatar *Image `json:"avatar,omitempty"` + // ChannelID is the new channel id this webhook should be moved to. ChannelID discord.Snowflake `json:"channel_id,omitempty"` } +// ModifyWebhook modifies a webhook. +// +// Requires the MANAGE_WEBHOOKS permission. func (c *Client) ModifyWebhook( - webhookID discord.Snowflake, - data ModifyWebhookData) (*discord.Webhook, error) { + webhookID discord.Snowflake, data ModifyWebhookData) (*discord.Webhook, error) { var w *discord.Webhook - return w, c.RequestJSON(&w, "PATCH", EndpointWebhooks+webhookID.String()) + return w, c.RequestJSON( + &w, "PATCH", + EndpointWebhooks+webhookID.String(), + httputil.WithJSONBody(data), + ) } +// ModifyWebhookWithToken is the same as above, except this call does not +// require authentication, does not accept a channel_id parameter in the body, +// and does not return a user in the webhook object. func (c *Client) ModifyWebhookWithToken( - webhookID discord.Snowflake, - data ModifyWebhookData, token string) (*discord.Webhook, error) { + webhookID discord.Snowflake, data ModifyWebhookData, token string) (*discord.Webhook, error) { var w *discord.Webhook - return w, c.RequestJSON(&w, "PATCH", EndpointWebhooks+webhookID.String()+"/"+token) + return w, c.RequestJSON( + &w, "PATCH", + EndpointWebhooks+webhookID.String()+"/"+token, + httputil.WithJSONBody(data)) } +// DeleteWebhook deletes a webhook permanently. +// +// Requires the MANAGE_WEBHOOKS permission. func (c *Client) DeleteWebhook(webhookID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointWebhooks+webhookID.String()) } +// DeleteWebhookWithToken is the same as above, except this call does not +// require authentication. func (c *Client) DeleteWebhookWithToken(webhookID discord.Snowflake, token string) error { return c.FastRequest("DELETE", EndpointWebhooks+webhookID.String()+"/"+token) } diff --git a/discord/message.go b/discord/message.go index 2f7e4f0..a13fd5b 100644 --- a/discord/message.go +++ b/discord/message.go @@ -1,5 +1,7 @@ package discord +import "github.com/diamondburned/arikawa/utils/json/enum" + type Message struct { ID Snowflake `json:"id,string"` Type MessageType `json:"type"` @@ -81,14 +83,15 @@ const ( GuildDiscoveryRequalifiedMessage ) -type MessageFlags uint32 +type MessageFlags enum.Enum -const ( - CrosspostedMessage MessageFlags = 1 << iota - MessageIsCrosspost - SuppressEmbeds - SourceMessageDeleted - UrgentMessage +var ( + NullMessage MessageFlags = enum.Null + CrosspostedMessage MessageFlags = 1 + MessageIsCrosspost MessageFlags = 2 + SuppressEmbeds MessageFlags = 4 + SourceMessageDeleted MessageFlags = 8 + UrgentMessage MessageFlags = 16 ) type ChannelMention struct { diff --git a/discord/permission.go b/discord/permission.go index dbbf0c1..18e4426 100644 --- a/discord/permission.go +++ b/discord/permission.go @@ -2,72 +2,72 @@ package discord type Permissions uint64 -const ( +var ( // Allows creation of instant invites - PermissionCreateInstantInvite Permissions = 1 << iota + PermissionCreateInstantInvite Permissions = 1 << 0 // Allows kicking members - PermissionKickMembers + PermissionKickMembers Permissions = 1 << 1 // Allows banning members - PermissionBanMembers + PermissionBanMembers Permissions = 1 << 2 // Allows all permissions and bypasses channel permission overwrites - PermissionAdministrator + PermissionAdministrator Permissions = 1 << 3 // Allows management and editing of channels - PermissionManageChannels + PermissionManageChannels Permissions = 1 << 4 // Allows management and editing of the guild - PermissionManageGuild + PermissionManageGuild Permissions = 1 << 5 // Allows for the addition of reactions to messages - PermissionAddReactions + PermissionAddReactions Permissions = 1 << 6 // Allows for viewing of audit logs - PermissionViewAuditLog + PermissionViewAuditLog Permissions = 1 << 7 // Allows for using priority speaker in a voice channel - PermissionPrioritySpeaker + PermissionPrioritySpeaker Permissions = 1 << 8 // Allows the user to go live - PermissionStream + PermissionStream Permissions = 1 << 9 // Allows guild members to view a channel, which includes reading messages // in text channels - PermissionViewChannel + PermissionViewChannel Permissions = 1 << 10 // Allows for sending messages in a channel - PermissionSendMessages + PermissionSendMessages Permissions = 1 << 11 // Allows for sending of /tts messages - PermissionSendTTSMessages + PermissionSendTTSMessages Permissions = 1 << 12 // Allows for deletion of other users messages - PermissionManageMessages + PermissionManageMessages Permissions = 1 << 13 // Links sent by users with this permission will be auto-embedded - PermissionEmbedLinks + PermissionEmbedLinks Permissions = 1 << 14 // Allows for uploading images and files - PermissionAttachFiles + PermissionAttachFiles Permissions = 1 << 15 // Allows for reading of message history - PermissionReadMessageHistory + PermissionReadMessageHistory Permissions = 1 << 16 // Allows for using the @everyone tag to notify all users in a channel, // and the @here tag to notify all online users in a channel - PermissionMentionEveryone + PermissionMentionEveryone Permissions = 1 << 17 // Allows the usage of custom emojis from other servers - PermissionUseExternalEmojis + PermissionUseExternalEmojis Permissions = 1 << 18 - _ // ? + // ? // Allows for joining of a voice channel - PermissionConnect + PermissionConnect Permissions = 1 << 20 // Allows for speaking in a voice channel - PermissionSpeak + PermissionSpeak Permissions = 1 << 21 // Allows for muting members in a voice channel - PermissionMuteMembers + PermissionMuteMembers Permissions = 1 << 22 // Allows for deafening of members in a voice channel - PermissionDeafenMembers + PermissionDeafenMembers Permissions = 1 << 23 // Allows for moving of members between voice channels - PermissionMoveMembers + PermissionMoveMembers Permissions = 1 << 24 // Allows for using voice-activity-detection in a voice channel - PermissionUseVAD + PermissionUseVAD Permissions = 1 << 25 // Allows for modification of own nickname - PermissionChangeNickname + PermissionChangeNickname Permissions = 1 << 26 // Allows for modification of other users nicknames - PermissionManageNicknames + PermissionManageNicknames Permissions = 1 << 27 // Allows management and editing of roles - PermissionManageRoles + PermissionManageRoles Permissions = 1 << 28 // Allows management and editing of webhooks - PermissionManageWebhooks + PermissionManageWebhooks Permissions = 1 << 29 // Allows management and editing of emojis - PermissionManageEmojis + PermissionManageEmojis Permissions = 1 << 30 PermissionAllText = 0 | PermissionViewChannel | diff --git a/utils/json/option/custom.go b/utils/json/option/custom.go index f6c4eba..e4d6b96 100644 --- a/utils/json/option/custom.go +++ b/utils/json/option/custom.go @@ -1,6 +1,10 @@ package option -import "github.com/diamondburned/arikawa/discord" +import ( + "strconv" + + "github.com/diamondburned/arikawa/discord" +) // ================================ Seconds ================================ @@ -20,3 +24,47 @@ type Color = *discord.Color // NewString creates a new Color with the value of the passed discord.Color. func NewColor(s discord.Color) Color { return &s } + +// ================================ NullableColor ================================ + +// Nullable is a nullable version of discord.Color. +type NullableColor = *nullableColor + +type nullableColor struct { + Val discord.Color + Init bool +} + +// NullColor serializes to JSON null. +var NullColor = &nullableColor{} + +// NewNullableColor creates a new non-null NullableColor using the value of the +// passed discord.Color. +func NewNullableColor(v discord.Color) NullableColor { + return &nullableColor{ + Val: v, + Init: true, + } +} + +func (i nullableColor) MarshalJSON() ([]byte, error) { + if !i.Init { + return []byte("null"), nil + } + return []byte(strconv.FormatUint(uint64(i.Val), 10)), nil +} + +func (i *nullableColor) UnmarshalJSON(json []byte) error { + s := string(json) + + if s == "null" { + i.Init = false + return nil + } + + v, err := strconv.ParseUint(s, 10, 32) + + i.Val = discord.Color(v) + + return err +} diff --git a/utils/json/option/number.go b/utils/json/option/number.go index 76a69fe..99af693 100644 --- a/utils/json/option/number.go +++ b/utils/json/option/number.go @@ -77,7 +77,7 @@ type nullableInt struct { Init bool } -// NullUint serializes to JSON null. +// NullInt serializes to JSON null. var NullInt = &nullableUint{} // NewInt creates a new non-null NullableInt using the value of the passed int.