From f34714e08b7ea0a8ea7b13d2674b00d7e099097e Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 29 Apr 2021 18:09:35 +0200 Subject: [PATCH 01/22] first component stuff --- api/component.go | 34 ++++++++++++++++++++++++++++++++++ api/message.go | 3 ++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 api/component.go diff --git a/api/component.go b/api/component.go new file mode 100644 index 00000000..8679f98b --- /dev/null +++ b/api/component.go @@ -0,0 +1,34 @@ +package api + +type ComponentType int + +const ( + ComponentTypeButtons = iota + 1 + ComponentTypeButton +) + +type ComponentStyle int + +const ( + ComponentStyleBlurple = iota + 1 + ComponentStyleGrey + ComponentStyleGreen + ComponentStyleRed + ComponentStyleHyperlink +) + +type Component struct { + ComponentType ComponentType `json:"type"` + Style *ComponentStyle `json:"style,omitempty"` + CustomID string `json:"custom_id,omitempty"` + Label string `json:"label,omitempty"` + URL string `json:"url,omitempty"` + Emoji *Emoji `json:"emoji,omitempty"` + Disabled bool `json:"disabled,omitempty"` + Components []*Component `json:"components,omitempty"` +} + +type Emoji struct { + Name string `json:"name,omitempty"` + ID Snowflake `json:"id,omitempty"` +} diff --git a/api/message.go b/api/message.go index ad5906f9..b7723b1a 100644 --- a/api/message.go +++ b/api/message.go @@ -166,6 +166,7 @@ type Message struct { Attachments []*MessageAttachment `json:"attachments"` TTS bool `json:"tts"` Embeds []*Embed `json:"embeds,omitempty"` + Components []*Component `json:"components,omitempty"` CreatedAt time.Time `json:"timestamp"` Mentions []interface{} `json:"mentions"` MentionEveryone bool `json:"mention_everyone"` @@ -186,7 +187,7 @@ type Message struct { Application *MessageApplication `json:"application,omitempty"` Stickers []*MessageSticker `json:"stickers,omitempty"` ReferencedMessage *Message `json:"referenced_message,omitempty"` - LastUpdated *time.Time + LastUpdated *time.Time `json:"last_updated,omitempty"` } // MessageReference is a reference to another message From f8072693d4585835cb161102cdc7336f52fc144d Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 30 Apr 2021 13:25:34 +0200 Subject: [PATCH 02/22] more button stuff --- api/audio_controller.go | 2 +- api/buttons.go | 21 ++++++ api/component.go | 26 ++------ api/entity_builder.go | 2 + api/events/guild_invite_events.go | 2 + api/events/guild_message_reaction_events.go | 2 + api/events/interaction_events.go | 13 +++- api/events/listener_adapter.go | 5 ++ api/events/self_update_events.go | 2 +- api/events/user_events.go | 1 + api/gateway_commands.go | 2 +- api/interaction.go | 39 +++++++---- api/interaction_followup.go | 7 ++ api/interaction_response.go | 12 +++- api/message.go | 2 + api/message_builder.go | 6 ++ api/options.go | 2 +- example/examplebot.go | 45 ++++++------- internal/disgo_builder_impl.go | 8 +-- internal/disgo_impl.go | 6 +- internal/entity_builder_impl.go | 64 +++++++++++-------- .../handlers/interaction_create_handler.go | 42 ++++++++---- .../interaction_create_webhook_handler.go | 8 +-- 23 files changed, 200 insertions(+), 119 deletions(-) create mode 100644 api/buttons.go diff --git a/api/audio_controller.go b/api/audio_controller.go index 4819ca7a..ae9e8388 100644 --- a/api/audio_controller.go +++ b/api/audio_controller.go @@ -4,7 +4,7 @@ import "errors" // errors returned when no gateway or ws conn exists var ( - ErrNoGateway = errors.New("no gateway initialized") + ErrNoGateway = errors.New("no gateway initialized") ErrNoGatewayConn = errors.New("no active gateway connection found") ) diff --git a/api/buttons.go b/api/buttons.go new file mode 100644 index 00000000..a06be648 --- /dev/null +++ b/api/buttons.go @@ -0,0 +1,21 @@ +package api + +type Buttons struct { + Component + Buttons []*Button `json:"components,omitempty"` +} + +type Button struct { + Component + Style *Style `json:"style,omitempty"` + CustomID string `json:"custom_id,omitempty"` + Label string `json:"label,omitempty"` + URL string `json:"url,omitempty"` + Emoji *Emoji `json:"emoji,omitempty"` + Disabled bool `json:"disabled,omitempty"` +} + +type Emoji struct { + Name string `json:"name,omitempty"` + ID Snowflake `json:"id,omitempty"` +} diff --git a/api/component.go b/api/component.go index 8679f98b..e6fde0f8 100644 --- a/api/component.go +++ b/api/component.go @@ -7,28 +7,16 @@ const ( ComponentTypeButton ) -type ComponentStyle int +type Style int const ( - ComponentStyleBlurple = iota + 1 - ComponentStyleGrey - ComponentStyleGreen - ComponentStyleRed - ComponentStyleHyperlink + StyleBlurple = iota + 1 + StyleGrey + StyleGreen + StyleRed + StyleHyperlink ) type Component struct { - ComponentType ComponentType `json:"type"` - Style *ComponentStyle `json:"style,omitempty"` - CustomID string `json:"custom_id,omitempty"` - Label string `json:"label,omitempty"` - URL string `json:"url,omitempty"` - Emoji *Emoji `json:"emoji,omitempty"` - Disabled bool `json:"disabled,omitempty"` - Components []*Component `json:"components,omitempty"` -} - -type Emoji struct { - Name string `json:"name,omitempty"` - ID Snowflake `json:"id,omitempty"` + Type ComponentType `json:"type"` } diff --git a/api/entity_builder.go b/api/entity_builder.go index c97a6379..ad95c3e0 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -16,6 +16,8 @@ type EntityBuilder interface { Disgo() Disgo CreateInteraction(interaction *Interaction, updateCache CacheStrategy) *Interaction + CreateComponentInteraction(interactionData *ComponentInteractionData, updateCache CacheStrategy) *ComponentInteractionData + CreateApplicationCommandInteraction(interactionData *SlashCommandInteractionData, updateCache CacheStrategy) *SlashCommandInteractionData CreateGlobalCommand(command *Command, updateCache CacheStrategy) *Command diff --git a/api/events/guild_invite_events.go b/api/events/guild_invite_events.go index d2d4b054..fc66ca8d 100644 --- a/api/events/guild_invite_events.go +++ b/api/events/guild_invite_events.go @@ -35,10 +35,12 @@ func (e GenericGuildInviteEvent) TextChannel() *api.TextChannel { func (e GenericGuildInviteEvent) VoiceChannel() *api.VoiceChannel { return e.Disgo().Cache().VoiceChannel(e.ChannelID) } + // StoreChannel returns the api.StoreChannel the GenericGuildInviteEvent happened in(returns nil if the api.StoreChannel is uncached or api.CacheFlagStoreChannels is disabled) func (e GenericGuildInviteEvent) StoreChannel() *api.StoreChannel { return e.Disgo().Cache().StoreChannel(e.ChannelID) } + // Category returns the api.Category the GenericGuildInviteEvent happened in(returns nil if the api.Category is uncached or api.CacheFlagCategories is disabled) func (e GenericGuildInviteEvent) Category() *api.Category { return e.Disgo().Cache().Category(e.ChannelID) diff --git a/api/events/guild_message_reaction_events.go b/api/events/guild_message_reaction_events.go index 97fd5e9e..d9f70104 100644 --- a/api/events/guild_message_reaction_events.go +++ b/api/events/guild_message_reaction_events.go @@ -1,6 +1,7 @@ package events import "github.com/DisgoOrg/disgo/api" + // GenericGuildMessageReactionEvent is called upon receiving DMMessageReactionAddEvent or DMMessageReactionRemoveEvent type GenericGuildMessageReactionEvent struct { GenericGuildMessageEvent @@ -8,6 +9,7 @@ type GenericGuildMessageReactionEvent struct { Member *api.Member MessageReaction api.MessageReaction } + // GuildMessageReactionAddEvent indicates that a api.Member added a api.MessageReaction to a api.Message in a api.TextChannel(requires the api.GatewayIntentsGuildMessageReactions) type GuildMessageReactionAddEvent struct { GenericGuildMessageReactionEvent diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index bc9611d3..a2c2a0fa 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -10,6 +10,9 @@ import ( type GenericInteractionEvent struct { GenericEvent *api.Interaction + ResponseChannel chan *api.InteractionResponse + FromWebhook bool + Replied bool } // Guild returns the api.Guild from the api.Cache @@ -55,14 +58,12 @@ func (e GenericInteractionEvent) GuildChannel() *api.GuildChannel { // SlashCommandEvent indicates that a slash api.Command was ran in a api.Guild type SlashCommandEvent struct { GenericInteractionEvent - ResponseChannel chan *api.InteractionResponse - FromWebhook bool CommandID api.Snowflake CommandName string SubCommandName *string SubCommandGroupName *string Options []*api.Option - Replied bool + Resolved *api.Resolved } // CommandPath returns the api.Command path @@ -152,3 +153,9 @@ func (e *SlashCommandEvent) EditFollowup(messageID api.Snowflake, followupMessag func (e *SlashCommandEvent) DeleteFollowup(messageID api.Snowflake) error { return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID) } + +type ButtonClickEvent struct { + GenericInteractionEvent + CustomID *string `json:"custom_id,omitempty"` + ComponentType *api.ComponentType `json:"component_type,omitempty"` +} diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index 7c0f6978..615b4c79 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -124,6 +124,7 @@ type ListenerAdapter struct { // api.Interaction Events OnGenericInteractionEvent func(event *GenericInteractionEvent) OnSlashCommand func(event *SlashCommandEvent) + OnButtonClick func(event *ButtonClickEvent) // api.Message Events OnGenericMessageEvent func(event *GenericMessageEvent) @@ -510,6 +511,10 @@ func (l ListenerAdapter) OnEvent(event interface{}) { if listener := l.OnSlashCommand; listener != nil { listener(&e) } + case ButtonClickEvent: + if listener := l.OnButtonClick; listener != nil { + listener(&e) + } // api.Message Events case GenericMessageEvent: diff --git a/api/events/self_update_events.go b/api/events/self_update_events.go index 4a12a6c4..61221f1c 100644 --- a/api/events/self_update_events.go +++ b/api/events/self_update_events.go @@ -7,6 +7,6 @@ import ( // SelfUpdateEvent is called when something about this api.User updates type SelfUpdateEvent struct { GenericEvent - Self *api.User + Self *api.User OldSelf *api.User } diff --git a/api/events/user_events.go b/api/events/user_events.go index 8be1d2ff..0ae3381a 100644 --- a/api/events/user_events.go +++ b/api/events/user_events.go @@ -16,6 +16,7 @@ type UserUpdateEvent struct { GenericUserEvent OldUser *api.User } + // UserTypingEvent indicates that a api.User started typing in a api.DMChannel or api.TextChannel(requires the api.GatewayIntentsDirectMessageTyping and/or api.GatewayIntentsGuildMessageTyping) type UserTypingEvent struct { GenericUserEvent diff --git a/api/gateway_commands.go b/api/gateway_commands.go index 8791bd62..d5c983af 100644 --- a/api/gateway_commands.go +++ b/api/gateway_commands.go @@ -24,7 +24,7 @@ type IdentifyCommand struct { Properties IdentifyCommandDataProperties `json:"properties"` Compress bool `json:"compress,omitempty"` LargeThreshold int `json:"large_threshold,omitempty"` - GatewayIntents GatewayIntents `json:"GatewayIntents"` + GatewayIntents GatewayIntents `json:"GatewayIntents"` // Todo: Add presence property here, need presence methods/struct // Todo: Add shard property here, need to discuss } diff --git a/api/interaction.go b/api/interaction.go index 20cdbba4..ee6312bf 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -1,5 +1,7 @@ package api +import "encoding/json" + // InteractionType is the type of Interaction type InteractionType int @@ -7,23 +9,34 @@ type InteractionType int const ( InteractionTypePing InteractionType = iota + 1 InteractionTypeApplicationCommand + InteractionTypeComponent ) +type FullInteraction struct { + *Interaction + Data json.RawMessage `json:"data,omitempty"` +} + // An Interaction is the slash command object you receive when a user uses one of your commands type Interaction struct { - ID Snowflake `json:"id"` - Type InteractionType `json:"type"` - Data *InteractionData `json:"data,omitempty"` - GuildID *Snowflake `json:"guild_id,omitempty"` - ChannelID *Snowflake `json:"channel_id,omitempty"` - Member *Member `json:"member,omitempty"` - User *User `json:"User,omitempty"` - Token string `json:"token"` - Version int `json:"version"` -} - -// InteractionData is the command data payload -type InteractionData struct { + ID Snowflake `json:"id"` + Type InteractionType `json:"type"` + GuildID *Snowflake `json:"guild_id,omitempty"` + ChannelID *Snowflake `json:"channel_id,omitempty"` + Member *Member `json:"member,omitempty"` + User *User `json:"User,omitempty"` + Token string `json:"token"` + Version int `json:"version"` +} + +// ComponentInteractionData is the command data payload +type ComponentInteractionData struct { + CustomID *string `json:"custom_id,omitempty"` + Name *string `json:"component_type,omitempty"` +} + +// SlashCommandInteractionData is the command data payload +type SlashCommandInteractionData struct { ID Snowflake `json:"id"` Name string `json:"name"` Resolved *Resolved `json:"resolved"` diff --git a/api/interaction_followup.go b/api/interaction_followup.go index 529d9f12..7fb1af43 100644 --- a/api/interaction_followup.go +++ b/api/interaction_followup.go @@ -7,6 +7,7 @@ type FollowupMessage struct { Content *string `json:"content,omitempty"` TTS *bool `json:"tts,omitempty"` Embeds []*Embed `json:"embeds,omitempty"` + Components []interface{} `json:"components,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` Flags *MessageFlags `json:"flags,omitempty"` } @@ -70,6 +71,12 @@ func (b *FollowupMessageBuilder) RemoveEmbed(index int) *FollowupMessageBuilder return b } +// SetComponents sets the Component(s) of the FollowupMessage +func (b *FollowupMessageBuilder) SetComponents(components ...interface{}) *FollowupMessageBuilder { + b.Components = components + return b +} + // SetAllowedMentions sets the allowed mentions of the FollowupMessage func (b *FollowupMessageBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *FollowupMessageBuilder { b.AllowedMentions = allowedMentions diff --git a/api/interaction_response.go b/api/interaction_response.go index 4df2f0dd..f99cddee 100644 --- a/api/interaction_response.go +++ b/api/interaction_response.go @@ -25,8 +25,9 @@ type InteractionResponseData struct { TTS *bool `json:"tts,omitempty"` Content *string `json:"content,omitempty"` Embeds []*Embed `json:"embeds,omitempty"` + Components []interface{} `json:"components,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - Flags *MessageFlags `json:"flags,omitempty"` + Flags *MessageFlags `json:"flags,omitempty"` } // InteractionResponseBuilder allows you to create an InteractionResponse with ease @@ -120,6 +121,15 @@ func (b *InteractionResponseBuilder) RemoveEmbed(i int) *InteractionResponseBuil return b } +// SetComponents sets the Component(s) of the InteractionResponse +func (b *InteractionResponseBuilder) SetComponents(components ...interface{}) *InteractionResponseBuilder { + if b.Data == nil { + b.Data = &InteractionResponseData{} + } + b.Data.Components = components + return b +} + // SetAllowedMentions sets the allowed mentions of the InteractionResponse func (b *InteractionResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *InteractionResponseBuilder { if b.Data == nil { diff --git a/api/message.go b/api/message.go index b7723b1a..e7a9d17c 100644 --- a/api/message.go +++ b/api/message.go @@ -266,6 +266,7 @@ type MessageReaction struct { // MessageUpdate is used to edit a Message type MessageUpdate struct { Content *string `json:"content,omitempty"` + Components []*Component `json:"components,omitempty"` Embed *Embed `json:"embed,omitempty"` Flags *MessageFlags `json:"flags,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` @@ -274,6 +275,7 @@ type MessageUpdate struct { // MessageCreate is the struct to create a new Message with type MessageCreate struct { Content *string `json:"content,omitempty"` + Components []*Component `json:"components,omitempty"` TTS *bool `json:"tts,omitempty"` Embed *Embed `json:"embed,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` diff --git a/api/message_builder.go b/api/message_builder.go index 2d28e544..7173c758 100644 --- a/api/message_builder.go +++ b/api/message_builder.go @@ -51,6 +51,12 @@ func (b *MessageBuilder) SetEmbed(embed *Embed) *MessageBuilder { return b } +// SetComponents sets the Component(s) of the Message +func (b *MessageBuilder) SetComponents(components ...*Component) *MessageBuilder { + b.Components = components + return b +} + // SetAllowedMentions sets the AllowedMentions of the Message func (b *MessageBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *MessageBuilder { b.AllowedMentions = allowedMentions diff --git a/api/options.go b/api/options.go index e29d6059..433d0979 100644 --- a/api/options.go +++ b/api/options.go @@ -9,7 +9,7 @@ import ( // Options is the configuration used when creating the client type Options struct { Logger log.Logger - GatewayIntents GatewayIntents + GatewayIntents GatewayIntents RestTimeout int EnableWebhookInteractions bool ListenPort int diff --git a/example/examplebot.go b/example/examplebot.go index 2fff91c4..6d427854 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -224,32 +224,25 @@ func slashCommandListener(event *events.SlashCommandEvent) { ) case "test": - go func() { - _ = event.Acknowledge() - - time.Sleep(2 * time.Second) - _, _ = event.EditOriginal(api.NewFollowupMessageBuilder(). - SetEmbeds(api.NewEmbedBuilder(). - SetDescription("finished with thinking"). - Build(), - ).Build(), - ) - - time.Sleep(1 * time.Second) - _, _ = event.SendFollowup(api.NewFollowupMessageBuilder(). - SetEmbeds(api.NewEmbedBuilder(). - SetDescription("followup 1"). - Build(), - ).Build(), - ) - - time.Sleep(1 * time.Second) - _, _ = event.SendFollowup(api.NewFollowupMessageBuilder(). - SetEphemeral(true). - SetContent("followup 2 only you can see"). - Build(), - ) - }() + _ = event.Reply(api.NewInteractionResponseBuilder(). + SetEphemeral(true). + SetContent("followup 2 only you can see"). + SetComponents(&api.Buttons{ + Component: api.Component{ + Type: api.ComponentTypeButtons, + }, + Buttons: []*api.Button{ + { + Component: api.Component{ + Type: api.ComponentTypeButton, + }, + CustomID: "1", + Label: "test", + }, + }, + }). + Build(), + ) case "addrole": user := event.Option("member").User() diff --git a/internal/disgo_builder_impl.go b/internal/disgo_builder_impl.go index 0de42ef4..853d54ab 100644 --- a/internal/disgo_builder_impl.go +++ b/internal/disgo_builder_impl.go @@ -29,7 +29,7 @@ type DisgoBuilderImpl struct { memberCachePolicy api.MemberCachePolicy messageCachePolicy api.MessageCachePolicy cacheFlags api.CacheFlags - GatewayIntents api.GatewayIntents + gatewayIntents api.GatewayIntents rawGatewayEventsEnabled bool entityBuilder api.EntityBuilder eventManager api.EventManager @@ -60,8 +60,8 @@ func (b *DisgoBuilderImpl) SetHTTPClient(httpClient *http.Client) api.DisgoBuild } // SetGatewayIntents sets the api.GatewayIntents to connect to discord -func (b *DisgoBuilderImpl) SetGatewayIntents(GatewayIntents api.GatewayIntents) api.DisgoBuilder { - b.GatewayIntents = GatewayIntents +func (b *DisgoBuilderImpl) SetGatewayIntents(gatewayIntents api.GatewayIntents) api.DisgoBuilder { + b.gatewayIntents = gatewayIntents return b } @@ -204,7 +204,7 @@ func (b *DisgoBuilderImpl) Build() (api.Disgo, error) { } disgo.audioController = b.audioController - disgo.GatewayIntents = b.GatewayIntents + disgo.gatewayIntents = b.gatewayIntents if b.entityBuilder == nil { b.entityBuilder = newEntityBuilderImpl(disgo) diff --git a/internal/disgo_impl.go b/internal/disgo_impl.go index ddb4bef4..901256dd 100644 --- a/internal/disgo_impl.go +++ b/internal/disgo_impl.go @@ -18,7 +18,7 @@ func New(token string, options api.Options) (api.Disgo, error) { disgo := &DisgoImpl{ botToken: token, - GatewayIntents: options.GatewayIntents, + gatewayIntents: options.GatewayIntents, largeThreshold: options.LargeThreshold, logger: options.Logger, rawGatewayEventsEnabled: options.RawGatewayEventsEnabled, @@ -55,7 +55,7 @@ type DisgoImpl struct { logger log.Logger gateway api.Gateway restClient api.RestClient - GatewayIntents api.GatewayIntents + gatewayIntents api.GatewayIntents rawGatewayEventsEnabled bool entityBuilder api.EntityBuilder eventManager api.EventManager @@ -159,7 +159,7 @@ func (d *DisgoImpl) Cache() api.Cache { // GatewayIntents returns the GatewayIntents originally specified when creating the client func (d *DisgoImpl) GatewayIntents() api.GatewayIntents { // clones the GatewayIntents so they can't be modified - c := d.GatewayIntents + c := d.gatewayIntents return c } diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index f4e9744a..a271f39c 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -14,21 +14,18 @@ type EntityBuilderImpl struct { } // Disgo returns the api.Disgo client -func (b EntityBuilderImpl) Disgo() api.Disgo { +func (b *EntityBuilderImpl) Disgo() api.Disgo { return b.disgo } -// CreateInteraction returns a new api.Interaction entity -func (b EntityBuilderImpl) CreateInteraction(interaction *api.Interaction, updateCache api.CacheStrategy) *api.Interaction { - if interaction.Member != nil { - interaction.Member = b.CreateMember(*interaction.GuildID, interaction.Member, api.CacheStrategyYes) - } - if interaction.User != nil { - interaction.User = b.CreateUser(interaction.User, updateCache) - } +func (b *EntityBuilderImpl) CreateComponentInteraction(interactionData *api.ComponentInteractionData, updateCache api.CacheStrategy) *api.ComponentInteractionData { + + return interactionData +} - if interaction.Data != nil && interaction.Data.Resolved != nil { - resolved := interaction.Data.Resolved +func (b *EntityBuilderImpl) CreateApplicationCommandInteraction(interactionData *api.SlashCommandInteractionData, updateCache api.CacheStrategy) *api.SlashCommandInteractionData { + if interactionData.Resolved != nil { + resolved := interactionData.Resolved if resolved.Users != nil { for _, user := range resolved.Users { user = b.CreateUser(user, updateCache) @@ -37,12 +34,12 @@ func (b EntityBuilderImpl) CreateInteraction(interaction *api.Interaction, updat if resolved.Members != nil { for id, member := range resolved.Members { member.User = resolved.Users[id] - member = b.CreateMember(*interaction.GuildID, member, updateCache) + member = b.CreateMember(member.GuildID, member, updateCache) } } if resolved.Roles != nil { for _, role := range resolved.Roles { - role = b.CreateRole(*interaction.GuildID, role, updateCache) + role = b.CreateRole(role.GuildID, role, updateCache) } } // TODO how do we cache partial channels? @@ -53,11 +50,22 @@ func (b EntityBuilderImpl) CreateInteraction(interaction *api.Interaction, updat } }*/ } + return interactionData +} + +// CreateInteraction returns a new api.Interaction entity +func (b *EntityBuilderImpl) CreateInteraction(interaction *api.Interaction, updateCache api.CacheStrategy) *api.Interaction { + if interaction.Member != nil { + interaction.Member = b.CreateMember(*interaction.GuildID, interaction.Member, api.CacheStrategyYes) + } + if interaction.User != nil { + interaction.User = b.CreateUser(interaction.User, updateCache) + } return interaction } // CreateGlobalCommand returns a new api.Command entity -func (b EntityBuilderImpl) CreateGlobalCommand(command *api.Command, updateCache api.CacheStrategy) *api.Command { +func (b *EntityBuilderImpl) CreateGlobalCommand(command *api.Command, updateCache api.CacheStrategy) *api.Command { command.Disgo = b.Disgo() if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheGlobalCommand(command) @@ -66,7 +74,7 @@ func (b EntityBuilderImpl) CreateGlobalCommand(command *api.Command, updateCache } // CreateUser returns a new api.User entity -func (b EntityBuilderImpl) CreateUser(user *api.User, updateCache api.CacheStrategy) *api.User { +func (b *EntityBuilderImpl) CreateUser(user *api.User, updateCache api.CacheStrategy) *api.User { user.Disgo = b.Disgo() if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheUser(user) @@ -75,7 +83,7 @@ func (b EntityBuilderImpl) CreateUser(user *api.User, updateCache api.CacheStrat } // CreateMessage returns a new api.Message entity -func (b EntityBuilderImpl) CreateMessage(message *api.Message, updateCache api.CacheStrategy) *api.Message { +func (b *EntityBuilderImpl) CreateMessage(message *api.Message, updateCache api.CacheStrategy) *api.Message { message.Disgo = b.Disgo() if message.Member != nil { message.Member = b.CreateMember(*message.GuildID, message.Member, updateCache) @@ -91,7 +99,7 @@ func (b EntityBuilderImpl) CreateMessage(message *api.Message, updateCache api.C } // CreateGuild returns a new api.Guild entity -func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache api.CacheStrategy) *api.Guild { +func (b *EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache api.CacheStrategy) *api.Guild { guild.Disgo = b.Disgo() if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheGuild(guild) @@ -100,7 +108,7 @@ func (b EntityBuilderImpl) CreateGuild(guild *api.Guild, updateCache api.CacheSt } // CreateMember returns a new api.Member entity -func (b EntityBuilderImpl) CreateMember(guildID api.Snowflake, member *api.Member, updateCache api.CacheStrategy) *api.Member { +func (b *EntityBuilderImpl) CreateMember(guildID api.Snowflake, member *api.Member, updateCache api.CacheStrategy) *api.Member { member.Disgo = b.Disgo() member.GuildID = guildID member.User = b.CreateUser(member.User, updateCache) @@ -111,7 +119,7 @@ func (b EntityBuilderImpl) CreateMember(guildID api.Snowflake, member *api.Membe } // CreateVoiceState returns a new api.VoiceState entity -func (b EntityBuilderImpl) CreateVoiceState(guildID api.Snowflake, voiceState *api.VoiceState, updateCache api.CacheStrategy) *api.VoiceState { +func (b *EntityBuilderImpl) CreateVoiceState(guildID api.Snowflake, voiceState *api.VoiceState, updateCache api.CacheStrategy) *api.VoiceState { voiceState.Disgo = b.Disgo() voiceState.GuildID = guildID b.Disgo().Logger().Infof("voiceState: %+v", voiceState) @@ -123,7 +131,7 @@ func (b EntityBuilderImpl) CreateVoiceState(guildID api.Snowflake, voiceState *a } // CreateGuildCommand returns a new api.Command entity -func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *api.Command, updateCache api.CacheStrategy) *api.Command { +func (b *EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *api.Command, updateCache api.CacheStrategy) *api.Command { command.Disgo = b.Disgo() command.GuildID = &guildID if updateCache(b.Disgo()) { @@ -133,7 +141,7 @@ func (b EntityBuilderImpl) CreateGuildCommand(guildID api.Snowflake, command *ap } // CreateGuildCommandPermissions returns a new api.GuildCommandPermissions entity -func (b EntityBuilderImpl) CreateGuildCommandPermissions(guildCommandPermissions *api.GuildCommandPermissions, updateCache api.CacheStrategy) *api.GuildCommandPermissions { +func (b *EntityBuilderImpl) CreateGuildCommandPermissions(guildCommandPermissions *api.GuildCommandPermissions, updateCache api.CacheStrategy) *api.GuildCommandPermissions { guildCommandPermissions.Disgo = b.Disgo() if updateCache(b.Disgo()) && b.Disgo().Cache().CacheFlags().Has(api.CacheFlagCommandPermissions) { if cmd := b.Disgo().Cache().Command(guildCommandPermissions.ID); cmd != nil { @@ -144,7 +152,7 @@ func (b EntityBuilderImpl) CreateGuildCommandPermissions(guildCommandPermissions } // CreateRole returns a new api.Role entity -func (b EntityBuilderImpl) CreateRole(guildID api.Snowflake, role *api.Role, updateCache api.CacheStrategy) *api.Role { +func (b *EntityBuilderImpl) CreateRole(guildID api.Snowflake, role *api.Role, updateCache api.CacheStrategy) *api.Role { role.Disgo = b.Disgo() role.GuildID = guildID if updateCache(b.Disgo()) { @@ -154,7 +162,7 @@ func (b EntityBuilderImpl) CreateRole(guildID api.Snowflake, role *api.Role, upd } // CreateTextChannel returns a new api.TextChannel entity -func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.TextChannel { +func (b *EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.TextChannel { channel.Disgo = b.Disgo() textChannel := &api.TextChannel{ MessageChannel: api.MessageChannel{ @@ -171,7 +179,7 @@ func (b EntityBuilderImpl) CreateTextChannel(channel *api.Channel, updateCache a } // CreateVoiceChannel returns a new api.VoiceChannel entity -func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.VoiceChannel { +func (b *EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.VoiceChannel { channel.Disgo = b.Disgo() voiceChannel := &api.VoiceChannel{ GuildChannel: api.GuildChannel{ @@ -185,7 +193,7 @@ func (b EntityBuilderImpl) CreateVoiceChannel(channel *api.Channel, updateCache } // CreateStoreChannel returns a new api.StoreChannel entity -func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.StoreChannel { +func (b *EntityBuilderImpl) CreateStoreChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.StoreChannel { channel.Disgo = b.Disgo() storeChannel := &api.StoreChannel{ GuildChannel: api.GuildChannel{ @@ -199,7 +207,7 @@ func (b EntityBuilderImpl) CreateStoreChannel(channel *api.Channel, updateCache } // CreateCategory returns a new api.Category entity -func (b EntityBuilderImpl) CreateCategory(channel *api.Channel, updateCache api.CacheStrategy) *api.Category { +func (b *EntityBuilderImpl) CreateCategory(channel *api.Channel, updateCache api.CacheStrategy) *api.Category { channel.Disgo = b.Disgo() category := &api.Category{ GuildChannel: api.GuildChannel{ @@ -213,7 +221,7 @@ func (b EntityBuilderImpl) CreateCategory(channel *api.Channel, updateCache api. } // CreateDMChannel returns a new api.DMChannel entity -func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.DMChannel { +func (b *EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache api.CacheStrategy) *api.DMChannel { channel.Disgo = b.Disgo() dmChannel := &api.DMChannel{ MessageChannel: api.MessageChannel{ @@ -227,7 +235,7 @@ func (b EntityBuilderImpl) CreateDMChannel(channel *api.Channel, updateCache api } // CreateEmote returns a new api.Emote entity -func (b EntityBuilderImpl) CreateEmote(guildID api.Snowflake, emote *api.Emote, updateCache api.CacheStrategy) *api.Emote { +func (b *EntityBuilderImpl) CreateEmote(guildID api.Snowflake, emote *api.Emote, updateCache api.CacheStrategy) *api.Emote { emote.Disgo = b.Disgo() emote.GuildID = guildID if updateCache(b.Disgo()) { diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index b50c6d96..47299c57 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -1,6 +1,8 @@ package handlers import ( + "encoding/json" + "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/events" ) @@ -20,28 +22,37 @@ func (h InteractionCreateHandler) New() interface{} { // HandleGatewayEvent handles the specific raw gateway event func (h InteractionCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - interaction, ok := i.(*api.Interaction) + interaction, ok := i.(*api.FullInteraction) if !ok { return } handleInteraction(disgo, eventManager, sequenceNumber, interaction, nil) } -func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, interaction *api.Interaction, c chan *api.InteractionResponse) { +func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, fullInteraction *api.FullInteraction, c chan *api.InteractionResponse) { - interaction = disgo.EntityBuilder().CreateInteraction(interaction, api.CacheStrategyYes) + interaction := disgo.EntityBuilder().CreateInteraction(fullInteraction.Interaction, api.CacheStrategyYes) genericInteractionEvent := events.GenericInteractionEvent{ - GenericEvent: events.NewEvent(disgo, sequenceNumber), - Interaction: interaction, + GenericEvent: events.NewEvent(disgo, sequenceNumber), + Interaction: interaction, + ResponseChannel: c, + FromWebhook: c != nil, + Replied: false, } eventManager.Dispatch(genericInteractionEvent) - if interaction.Data != nil { - options := interaction.Data.Options + switch interaction.Type { + case api.InteractionTypeApplicationCommand: + var data *api.SlashCommandInteractionData + if err := json.Unmarshal(fullInteraction.Data, &data); err != nil { + disgo.Logger().Errorf("failed to unmarshal SlashCommandInteractionData: %s", err) + return + } + options := data.Options var subCommandName *string var subCommandGroupName *string if len(options) == 1 { - option := interaction.Data.Options[0] + option := data.Options[0] if option.Type == api.CommandOptionTypeSubCommandGroup { subCommandGroupName = &option.Name options = option.Options @@ -55,7 +66,7 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN var newOptions []*api.Option for _, optionData := range options { newOptions = append(newOptions, &api.Option{ - Resolved: interaction.Data.Resolved, + Resolved: data.Resolved, Name: optionData.Name, Type: optionData.Type, Value: optionData.Value, @@ -63,15 +74,18 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN } eventManager.Dispatch(events.SlashCommandEvent{ - ResponseChannel: c, - FromWebhook: c != nil, GenericInteractionEvent: genericInteractionEvent, - CommandID: interaction.Data.ID, - CommandName: interaction.Data.Name, + CommandID: data.ID, + CommandName: data.Name, SubCommandName: subCommandName, SubCommandGroupName: subCommandGroupName, Options: newOptions, - Replied: false, }) + case api.InteractionTypeComponent: + var data *api.ComponentInteractionData + if err := json.Unmarshal(fullInteraction.Data, &data); err != nil { + disgo.Logger().Errorf("failed to unmarshal ComponentInteractionData: %s", err) + return + } } } diff --git a/internal/handlers/interaction_create_webhook_handler.go b/internal/handlers/interaction_create_webhook_handler.go index 1751759f..c304e4eb 100644 --- a/internal/handlers/interaction_create_webhook_handler.go +++ b/internal/handlers/interaction_create_webhook_handler.go @@ -14,21 +14,21 @@ func (h InteractionCreateWebhookHandler) Event() api.GatewayEventType { // New constructs a new payload receiver for the raw gateway event func (h InteractionCreateWebhookHandler) New() interface{} { - return &api.Interaction{} + return &api.FullInteraction{} } // HandleWebhookEvent handles the specific raw gateway event func (h InteractionCreateWebhookHandler) HandleWebhookEvent(disgo api.Disgo, eventManager api.EventManager, c chan *api.InteractionResponse, i interface{}) { - interaction, ok := i.(*api.Interaction) + fullInteraction, ok := i.(*api.FullInteraction) if !ok { return } - if interaction.Type == api.InteractionTypePing { + if fullInteraction.Type == api.InteractionTypePing { c <- &api.InteractionResponse{ Type: api.InteractionResponseTypePong, } return } - handleInteraction(disgo, eventManager, -1, interaction, c) + handleInteraction(disgo, eventManager, -1, fullInteraction, c) } From 889c598a2e14be6699904bb5660233a6a327516e Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 1 May 2021 18:46:52 +0200 Subject: [PATCH 03/22] more button & sleect stuff --- api/button.go | 76 ++++++++ api/button_response.go | 109 ++++++++++++ api/buttons.go | 21 --- api/command_response.go | 116 +++++++++++++ api/component.go | 26 ++- api/events/interaction_events.go | 37 ++-- api/gateway_commands.go | 2 +- api/interaction.go | 7 +- api/interaction_response.go | 163 +----------------- api/message.go | 12 +- api/message_builder.go | 2 +- api/row.go | 15 ++ api/select.go | 31 ++++ example/examplebot.go | 90 ++++++---- .../handlers/interaction_create_handler.go | 12 +- 15 files changed, 476 insertions(+), 243 deletions(-) create mode 100644 api/button.go create mode 100644 api/button_response.go delete mode 100644 api/buttons.go create mode 100644 api/command_response.go create mode 100644 api/row.go create mode 100644 api/select.go diff --git a/api/button.go b/api/button.go new file mode 100644 index 00000000..ac33f552 --- /dev/null +++ b/api/button.go @@ -0,0 +1,76 @@ +package api + +func NewBlurpleButton(label string, customID string, emoji *Emoji, disabled bool) *Button { + return &Button{ + ComponentImpl: ComponentImpl{ + ComponentType: ComponentTypeButton, + }, + Style: StyleBlurple, + CustomID: customID, + Label: label, + Emoji: emoji, + Disabled: disabled, + } +} + +func NewGreyButton(label string, customID string, emoji *Emoji, disabled bool) *Button { + return &Button{ + ComponentImpl: ComponentImpl{ + ComponentType: ComponentTypeButton, + }, + Style: StyleGrey, + CustomID: customID, + Label: label, + Emoji: emoji, + Disabled: disabled, + } +} + +func NewGreenButton(label string, customID string, emoji *Emoji, disabled bool) *Button { + return &Button{ + ComponentImpl: ComponentImpl{ + ComponentType: ComponentTypeButton, + }, + Style: StyleGreen, + CustomID: customID, + Label: label, + Emoji: emoji, + Disabled: disabled, + } +} + +func NewRedButton(label string, customID string, emoji *Emoji, disabled bool) *Button { + return &Button{ + ComponentImpl: ComponentImpl{ + ComponentType: ComponentTypeButton, + }, + Style: StyleRed, + CustomID: customID, + Label: label, + Emoji: emoji, + Disabled: disabled, + } +} + +func NewLinkButton(label string, URL string, emoji *Emoji, disabled bool) *Button { + return &Button{ + ComponentImpl: ComponentImpl{ + ComponentType: ComponentTypeButton, + }, + Style: StyleHyperlink, + Label: label, + URL: URL, + Emoji: emoji, + Disabled: disabled, + } +} + +type Button struct { + ComponentImpl + Style Style `json:"style,omitempty"` + CustomID string `json:"custom_id,omitempty"` + Label string `json:"label,omitempty"` + URL string `json:"url,omitempty"` + Emoji *Emoji `json:"emoji,omitempty"` + Disabled bool `json:"disabled,omitempty"` +} \ No newline at end of file diff --git a/api/button_response.go b/api/button_response.go new file mode 100644 index 00000000..8f591e03 --- /dev/null +++ b/api/button_response.go @@ -0,0 +1,109 @@ +package api + +import "fmt" + +// The ButtonResponseData ... +type ButtonResponseData struct { + Content *string `json:"content"` + Embeds []*Embed `json:"embeds,omitempty"` + Components []Component `json:"components,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + Flags *MessageFlags `json:"flags,omitempty"` +} + +// ButtonResponseBuilder allows you to create an InteractionResponse with ease +type ButtonResponseBuilder struct { + ButtonResponseData +} + +// NewButtonResponseBuilder returns a new ButtonResponseBuilder +func NewButtonResponseBuilder() *ButtonResponseBuilder { + return &ButtonResponseBuilder{ + ButtonResponseData: ButtonResponseData{ + AllowedMentions: &DefaultInteractionAllowedMentions, + }, + } +} + +// SetContent sets the content of the InteractionResponse +func (b *ButtonResponseBuilder) SetContent(content string) *ButtonResponseBuilder { + b.Content = &content + return b +} + +// SetContentf sets the content of the InteractionResponse with format +func (b *ButtonResponseBuilder) SetContentf(content string, a ...interface{}) *ButtonResponseBuilder { + contentf := fmt.Sprintf(content, a...) + b.Content = &contentf + return b +} + +// SetEmbeds sets the embeds of the InteractionResponse +func (b *ButtonResponseBuilder) SetEmbeds(embeds ...*Embed) *ButtonResponseBuilder { + b.Embeds = embeds + return b +} + +// AddEmbeds adds multiple embeds to the InteractionResponse +func (b *ButtonResponseBuilder) AddEmbeds(embeds ...*Embed) *ButtonResponseBuilder { + b.Embeds = append(b.Embeds, embeds...) + return b +} + +// ClearEmbeds removes all of the embeds from the InteractionResponse +func (b *ButtonResponseBuilder) ClearEmbeds() *ButtonResponseBuilder { + if b != nil { + b.Embeds = []*Embed{} + } + return b +} + +// RemoveEmbed removes an embed from the InteractionResponse +func (b *ButtonResponseBuilder) RemoveEmbed(i int) *ButtonResponseBuilder { + if b != nil && len(b.Embeds) > i { + b.Embeds = append(b.Embeds[:i], b.Embeds[i+1:]...) + } + return b +} + +// SetComponents sets the Component(s) of the InteractionResponse +func (b *ButtonResponseBuilder) SetComponents(components ...Component) *ButtonResponseBuilder { + b.Components = components + return b +} + +// SetAllowedMentions sets the allowed mentions of the InteractionResponse +func (b *ButtonResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *ButtonResponseBuilder { + b.AllowedMentions = allowedMentions + return b +} + +// SetAllowedMentionsEmpty sets the allowed mentions of the InteractionResponse to nothing +func (b *ButtonResponseBuilder) SetAllowedMentionsEmpty() *ButtonResponseBuilder { + return b.SetAllowedMentions(&AllowedMentions{}) +} + +// SetFlags sets the message flags of the InteractionResponse +func (b *ButtonResponseBuilder) SetFlags(flags MessageFlags) *ButtonResponseBuilder { + b.Flags = &flags + return b +} + +// SetEphemeral adds/removes MessageFlagEphemeral to the message flags +func (b *ButtonResponseBuilder) SetEphemeral(ephemeral bool) *ButtonResponseBuilder { + if ephemeral { + *b.Flags = MessageFlagEphemeral + + } else { + *b.Flags |= MessageFlagEphemeral + } + return b +} + +// Build returns your built InteractionResponse +func (b *ButtonResponseBuilder) Build() *InteractionResponse { + return &InteractionResponse{ + Type: InteractionResponseTypeButtonResponse, + Data: &b.ButtonResponseData, + } +} diff --git a/api/buttons.go b/api/buttons.go deleted file mode 100644 index a06be648..00000000 --- a/api/buttons.go +++ /dev/null @@ -1,21 +0,0 @@ -package api - -type Buttons struct { - Component - Buttons []*Button `json:"components,omitempty"` -} - -type Button struct { - Component - Style *Style `json:"style,omitempty"` - CustomID string `json:"custom_id,omitempty"` - Label string `json:"label,omitempty"` - URL string `json:"url,omitempty"` - Emoji *Emoji `json:"emoji,omitempty"` - Disabled bool `json:"disabled,omitempty"` -} - -type Emoji struct { - Name string `json:"name,omitempty"` - ID Snowflake `json:"id,omitempty"` -} diff --git a/api/command_response.go b/api/command_response.go new file mode 100644 index 00000000..10188ccb --- /dev/null +++ b/api/command_response.go @@ -0,0 +1,116 @@ +package api + +import "fmt" + +// The CommandResponseData is used to specify the message_events options when creating an InteractionResponse +type CommandResponseData struct { + TTS *bool `json:"tts,omitempty"` + Content *string `json:"content,omitempty"` + Embeds []*Embed `json:"embeds,omitempty"` + Components []Component `json:"components,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + Flags MessageFlags `json:"flags,omitempty"` +} + +// CommandResponseBuilder allows you to create an InteractionResponse with ease +type CommandResponseBuilder struct { + CommandResponseData +} + +// NewCommandResponseBuilder returns a new CommandResponseBuilder +func NewCommandResponseBuilder() *CommandResponseBuilder { + return &CommandResponseBuilder{ + CommandResponseData: CommandResponseData{ + AllowedMentions: &DefaultInteractionAllowedMentions, + }, + } +} + +// SetTTS sets if the InteractionResponse is a tts message +func (b *CommandResponseBuilder) SetTTS(tts bool) *CommandResponseBuilder { + b.TTS = &tts + return b +} + +// SetContent sets the content of the InteractionResponse +func (b *CommandResponseBuilder) SetContent(content string) *CommandResponseBuilder { + b.Content = &content + return b +} + +// SetContentf sets the content of the InteractionResponse with format +func (b *CommandResponseBuilder) SetContentf(content string, a ...interface{}) *CommandResponseBuilder { + contentf := fmt.Sprintf(content, a...) + b.Content = &contentf + return b +} + +// SetEmbeds sets the embeds of the InteractionResponse +func (b *CommandResponseBuilder) SetEmbeds(embeds ...*Embed) *CommandResponseBuilder { + b.Embeds = embeds + return b +} + +// AddEmbeds adds multiple embeds to the InteractionResponse +func (b *CommandResponseBuilder) AddEmbeds(embeds ...*Embed) *CommandResponseBuilder { + b.Embeds = append(b.Embeds, embeds...) + return b +} + +// ClearEmbeds removes all of the embeds from the InteractionResponse +func (b *CommandResponseBuilder) ClearEmbeds() *CommandResponseBuilder { + if b != nil { + b.Embeds = []*Embed{} + } + return b +} + +// RemoveEmbed removes an embed from the InteractionResponse +func (b *CommandResponseBuilder) RemoveEmbed(i int) *CommandResponseBuilder { + if b != nil && len(b.Embeds) > i { + b.Embeds = append(b.Embeds[:i], b.Embeds[i+1:]...) + } + return b +} + +// SetComponents sets the Component(s) of the InteractionResponse +func (b *CommandResponseBuilder) SetComponents(components ...Component) *CommandResponseBuilder { + b.Components = components + return b +} + +// SetAllowedMentions sets the allowed mentions of the InteractionResponse +func (b *CommandResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *CommandResponseBuilder { + b.AllowedMentions = allowedMentions + return b +} + +// SetAllowedMentionsEmpty sets the allowed mentions of the InteractionResponse to nothing +func (b *CommandResponseBuilder) SetAllowedMentionsEmpty() *CommandResponseBuilder { + return b.SetAllowedMentions(&AllowedMentions{}) +} + +// SetFlags sets the message flags of the InteractionResponse +func (b *CommandResponseBuilder) SetFlags(flags MessageFlags) *CommandResponseBuilder { + b.Flags = flags + return b +} + +// SetEphemeral adds/removes MessageFlagEphemeral to the message flags +func (b *CommandResponseBuilder) SetEphemeral(ephemeral bool) *CommandResponseBuilder { + if ephemeral { + b.Flags = MessageFlagEphemeral + + } else { + b.Flags |= MessageFlagEphemeral + } + return b +} + +// Build returns your built InteractionResponse +func (b *CommandResponseBuilder) Build() *InteractionResponse { + return &InteractionResponse{ + Type: InteractionResponseTypeChannelMessageWithSource, + Data: &b.CommandResponseData, + } +} diff --git a/api/component.go b/api/component.go index e6fde0f8..dc1bf8c6 100644 --- a/api/component.go +++ b/api/component.go @@ -5,6 +5,7 @@ type ComponentType int const ( ComponentTypeButtons = iota + 1 ComponentTypeButton + ComponentTypeSelect ) type Style int @@ -17,6 +18,27 @@ const ( StyleHyperlink ) -type Component struct { - Type ComponentType `json:"type"` +type Component interface { + Type() ComponentType +} + +type ComponentImpl struct { + ComponentType ComponentType `json:"type"` +} + +func (t ComponentImpl) Type() ComponentType { + return t.ComponentType +} + +func NewCustomEmoji(emoteID Snowflake) *Emoji { + return &Emoji{ID: emoteID} +} + +func NewEmoji(name string) *Emoji { + return &Emoji{Name: name} +} + +type Emoji struct { + Name string `json:"name,omitempty"` + ID Snowflake `json:"id,omitempty"` } diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index a2c2a0fa..e99d9285 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -15,6 +15,21 @@ type GenericInteractionEvent struct { Replied bool } +// Reply replies to the api.Interaction with the provided api.InteractionResponse +func (e *GenericInteractionEvent) Reply(response *api.InteractionResponse) error { + if e.Replied { + return errors.New("you already replied to this interaction") + } + e.Replied = true + + if e.FromWebhook { + e.ResponseChannel <- response + return nil + } + + return e.Disgo().RestClient().SendInteractionResponse(e.Interaction.ID, e.Interaction.Token, response) +} + // Guild returns the api.Guild from the api.Cache func (e GenericInteractionEvent) Guild() *api.Guild { if e.Interaction.GuildID == nil { @@ -111,22 +126,7 @@ func (e SlashCommandEvent) OptionsT(optionType api.CommandOptionType) []*api.Opt // Acknowledge replies to the api.Interaction with api.InteractionResponseTypeDeferredChannelMessageWithSource func (e *SlashCommandEvent) Acknowledge() error { - return e.Reply(api.NewInteractionResponseBuilder().SetType(api.InteractionResponseTypeDeferredChannelMessageWithSource).Build()) -} - -// Reply replies to the api.Interaction with the provided api.InteractionResponse -func (e *SlashCommandEvent) Reply(response *api.InteractionResponse) error { - if e.Replied { - return errors.New("you already replied to this interaction") - } - e.Replied = true - - if e.FromWebhook { - e.ResponseChannel <- response - return nil - } - - return e.Disgo().RestClient().SendInteractionResponse(e.Interaction.ID, e.Interaction.Token, response) + return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredChannelMessageWithSource}) } // EditOriginal edits the original api.InteractionResponse @@ -156,6 +156,7 @@ func (e *SlashCommandEvent) DeleteFollowup(messageID api.Snowflake) error { type ButtonClickEvent struct { GenericInteractionEvent - CustomID *string `json:"custom_id,omitempty"` - ComponentType *api.ComponentType `json:"component_type,omitempty"` + CustomID string + ComponentType api.ComponentType + Message *api.Message } diff --git a/api/gateway_commands.go b/api/gateway_commands.go index d5c983af..6aae033f 100644 --- a/api/gateway_commands.go +++ b/api/gateway_commands.go @@ -24,7 +24,7 @@ type IdentifyCommand struct { Properties IdentifyCommandDataProperties `json:"properties"` Compress bool `json:"compress,omitempty"` LargeThreshold int `json:"large_threshold,omitempty"` - GatewayIntents GatewayIntents `json:"GatewayIntents"` + GatewayIntents GatewayIntents `json:"intents"` // Todo: Add presence property here, need presence methods/struct // Todo: Add shard property here, need to discuss } diff --git a/api/interaction.go b/api/interaction.go index ee6312bf..5bb0f78b 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -14,7 +14,8 @@ const ( type FullInteraction struct { *Interaction - Data json.RawMessage `json:"data,omitempty"` + Data json.RawMessage `json:"data,omitempty"` + Message *Message `json:"message,omitempty"` } // An Interaction is the slash command object you receive when a user uses one of your commands @@ -31,8 +32,8 @@ type Interaction struct { // ComponentInteractionData is the command data payload type ComponentInteractionData struct { - CustomID *string `json:"custom_id,omitempty"` - Name *string `json:"component_type,omitempty"` + CustomID string `json:"custom_id"` + Type ComponentType `json:"component_type"` } // SlashCommandInteractionData is the command data payload diff --git a/api/interaction_response.go b/api/interaction_response.go index f99cddee..efb45134 100644 --- a/api/interaction_response.go +++ b/api/interaction_response.go @@ -1,7 +1,5 @@ package api -import "fmt" - // InteractionResponseType indicates the type of slash command response, whether it's responding immediately or deferring to edit your response later type InteractionResponseType int @@ -12,165 +10,12 @@ const ( _ InteractionResponseTypeChannelMessageWithSource InteractionResponseTypeDeferredChannelMessageWithSource + _ + InteractionResponseTypeButtonResponse ) // InteractionResponse is how you answer interactions. If an answer is not sent within 3 seconds of receiving it, the interaction is failed, and you will be unable to respond to it. type InteractionResponse struct { - Type InteractionResponseType `json:"type"` - Data *InteractionResponseData `json:"data,omitempty"` -} - -// The InteractionResponseData is used to specify the message_events options when creating an InteractionResponse -type InteractionResponseData struct { - TTS *bool `json:"tts,omitempty"` - Content *string `json:"content,omitempty"` - Embeds []*Embed `json:"embeds,omitempty"` - Components []interface{} `json:"components,omitempty"` - AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - Flags *MessageFlags `json:"flags,omitempty"` -} - -// InteractionResponseBuilder allows you to create an InteractionResponse with ease -type InteractionResponseBuilder struct { - InteractionResponse -} - -// NewInteractionResponseBuilder returns a new InteractionResponseBuilder -func NewInteractionResponseBuilder() *InteractionResponseBuilder { - return &InteractionResponseBuilder{ - InteractionResponse{ - Type: InteractionResponseTypeChannelMessageWithSource, - Data: &InteractionResponseData{ - AllowedMentions: &DefaultInteractionAllowedMentions, - }, - }, - } -} - -// SetType sets the InteractionResponseType of the InteractionResponse -func (b *InteractionResponseBuilder) SetType(responseType InteractionResponseType) *InteractionResponseBuilder { - b.Type = responseType - return b -} - -// SetData sets the InteractionResponseData of the InteractionResponse -func (b *InteractionResponseBuilder) SetData(data *InteractionResponseData) *InteractionResponseBuilder { - b.Data = data - return b -} - -// SetTTS sets if the InteractionResponse is a tts message -func (b *InteractionResponseBuilder) SetTTS(tts bool) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - b.Data.TTS = &tts - return b -} - -// SetContent sets the content of the InteractionResponse -func (b *InteractionResponseBuilder) SetContent(content string) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - b.Data.Content = &content - return b -} - -// SetContentf sets the content of the InteractionResponse with format -func (b *InteractionResponseBuilder) SetContentf(content string, a ...interface{}) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - contentf := fmt.Sprintf(content, a...) - b.Data.Content = &contentf - return b -} - -// SetEmbeds sets the embeds of the InteractionResponse -func (b *InteractionResponseBuilder) SetEmbeds(embeds ...*Embed) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - b.Data.Embeds = embeds - return b -} - -// AddEmbeds adds multiple embeds to the InteractionResponse -func (b *InteractionResponseBuilder) AddEmbeds(embeds ...*Embed) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - b.Data.Embeds = append(b.Data.Embeds, embeds...) - return b -} - -// ClearEmbeds removes all of the embeds from the InteractionResponse -func (b *InteractionResponseBuilder) ClearEmbeds() *InteractionResponseBuilder { - if b.Data != nil { - b.Data.Embeds = []*Embed{} - } - return b -} - -// RemoveEmbed removes an embed from the InteractionResponse -func (b *InteractionResponseBuilder) RemoveEmbed(i int) *InteractionResponseBuilder { - if b.Data != nil && len(b.Data.Embeds) > i { - b.Data.Embeds = append(b.Data.Embeds[:i], b.Data.Embeds[i+1:]...) - } - return b -} - -// SetComponents sets the Component(s) of the InteractionResponse -func (b *InteractionResponseBuilder) SetComponents(components ...interface{}) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - b.Data.Components = components - return b -} - -// SetAllowedMentions sets the allowed mentions of the InteractionResponse -func (b *InteractionResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - b.Data.AllowedMentions = allowedMentions - return b -} - -// SetAllowedMentionsEmpty sets the allowed mentions of the InteractionResponse to nothing -func (b *InteractionResponseBuilder) SetAllowedMentionsEmpty() *InteractionResponseBuilder { - return b.SetAllowedMentions(&AllowedMentions{}) -} - -// SetFlags sets the message flags of the InteractionResponse -func (b *InteractionResponseBuilder) SetFlags(flags MessageFlags) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - b.Data.Flags = &flags - return b -} - -// SetEphemeral adds/removes MessageFlagEphemeral to the message flags -func (b *InteractionResponseBuilder) SetEphemeral(ephemeral bool) *InteractionResponseBuilder { - if b.Data == nil { - b.Data = &InteractionResponseData{} - } - if ephemeral { - if !b.Data.Flags.Has(MessageFlagEphemeral) { - b.Data.Flags.Add(MessageFlagEphemeral) - } - } else { - if b.Data.Flags.Has(MessageFlagEphemeral) { - b.Data.Flags.Remove(MessageFlagEphemeral) - } - } - return b -} - -// Build returns your built InteractionResponse -func (b *InteractionResponseBuilder) Build() *InteractionResponse { - return &b.InteractionResponse + Type InteractionResponseType `json:"type"` + Data interface{} `json:"data,omitempty"` } diff --git a/api/message.go b/api/message.go index e7a9d17c..ca0ad8a1 100644 --- a/api/message.go +++ b/api/message.go @@ -88,15 +88,15 @@ func (f MessageFlags) Missing(bit MessageFlags) bool { // Constants for MessageFlags const ( - MessageFlagNone MessageFlags = 0 - MessageFlagCrossposted MessageFlags = 1 << (iota - 1) + MessageFlagCrossposted MessageFlags = 1 << iota MessageFlagIsCrosspost MessageFlagSuppressEmbeds MessageFlagSourceMessageDeleted MessageFlagUrgent _ MessageFlagEphemeral - MessageFlagLoading // Message is an interaction of type 5, awaiting further response + MessageFlagLoading // Message is an interaction of type 5, awaiting further response + MessageFlagNone MessageFlags = 0 ) //MessageAttachment is used for files sent in a Message @@ -166,7 +166,7 @@ type Message struct { Attachments []*MessageAttachment `json:"attachments"` TTS bool `json:"tts"` Embeds []*Embed `json:"embeds,omitempty"` - Components []*Component `json:"components,omitempty"` + Components []Component `json:"components,omitempty"` CreatedAt time.Time `json:"timestamp"` Mentions []interface{} `json:"mentions"` MentionEveryone bool `json:"mention_everyone"` @@ -266,7 +266,7 @@ type MessageReaction struct { // MessageUpdate is used to edit a Message type MessageUpdate struct { Content *string `json:"content,omitempty"` - Components []*Component `json:"components,omitempty"` + Components []Component `json:"components,omitempty"` Embed *Embed `json:"embed,omitempty"` Flags *MessageFlags `json:"flags,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` @@ -275,7 +275,7 @@ type MessageUpdate struct { // MessageCreate is the struct to create a new Message with type MessageCreate struct { Content *string `json:"content,omitempty"` - Components []*Component `json:"components,omitempty"` + Components []Component `json:"components,omitempty"` TTS *bool `json:"tts,omitempty"` Embed *Embed `json:"embed,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` diff --git a/api/message_builder.go b/api/message_builder.go index 7173c758..950d9295 100644 --- a/api/message_builder.go +++ b/api/message_builder.go @@ -52,7 +52,7 @@ func (b *MessageBuilder) SetEmbed(embed *Embed) *MessageBuilder { } // SetComponents sets the Component(s) of the Message -func (b *MessageBuilder) SetComponents(components ...*Component) *MessageBuilder { +func (b *MessageBuilder) SetComponents(components ...Component) *MessageBuilder { b.Components = components return b } diff --git a/api/row.go b/api/row.go new file mode 100644 index 00000000..eb15d802 --- /dev/null +++ b/api/row.go @@ -0,0 +1,15 @@ +package api + +func NewRow(components ...Component) *Row { + return &Row{ + ComponentImpl: ComponentImpl{ + ComponentType: ComponentTypeButtons, + }, + Components: components, + } +} + +type Row struct { + ComponentImpl + Components []Component `json:"components,omitempty"` +} diff --git a/api/select.go b/api/select.go new file mode 100644 index 00000000..8fc76100 --- /dev/null +++ b/api/select.go @@ -0,0 +1,31 @@ +package api + +func NewSelect(customID string, placeholder string, minValues int, maxValues int, options ...*SelectOption) *Select { + return &Select{ + ComponentImpl: ComponentImpl{ + ComponentType: ComponentTypeSelect, + }, + CustomID: customID, + Placeholder: placeholder, + Options: options, + MinValues: minValues, + MaxValues: maxValues, + } +} + +type Select struct { + ComponentImpl + CustomID string `json:"custom_id,omitempty"` + Placeholder string `json:"placeholder,omitempty"` + Options []*SelectOption `json:"options,omitempty"` + MinValues int `json:"min_values,omitempty"` + MaxValues int `json:"max_values,omitempty"` +} + +type SelectOption struct { + Label string `json:"label"` + Value interface{} `json:"value"` + Default bool `json:"default,omitempty"` + Description string `json:"description"` + Emoji *Emoji `json:"emoji,omitempty"` +} diff --git a/example/examplebot.go b/example/examplebot.go index 6d427854..272f750c 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -34,13 +34,16 @@ func main() { dgo, err := disgo.NewBuilder(os.Getenv("token")). SetLogger(logger). + SetRawGatewayEventsEnabled(true). SetHTTPClient(client). SetGatewayIntents(api.GatewayIntentsGuilds | api.GatewayIntentsGuildMessages | api.GatewayIntentsGuildMembers). SetMemberCachePolicy(api.MemberCachePolicyAll). AddEventListeners(&events.ListenerAdapter{ + OnRawGateway: rawGatewayEventListener, OnGuildAvailable: guildAvailListener, OnGuildMessageCreate: messageListener, OnSlashCommand: slashCommandListener, + OnButtonClick: buttonClickListener, }). Build() if err != nil { @@ -168,11 +171,32 @@ func guildAvailListener(event *events.GuildAvailableEvent) { logger.Printf("guild loaded: %s", event.Guild.ID) } +func rawGatewayEventListener(event *events.RawGatewayEvent) { + if event.Type == api.GatewayEventInteractionCreate { + println(string(event.RawPayload)) + } +} + +func buttonClickListener(event *events.ButtonClickEvent) { + switch event.CustomID { + case "test": + err := event.Reply(&api.InteractionResponse{ + Type: api.InteractionResponseTypeButtonResponse, + Data: &api.ButtonResponseData{ + Content: nil, + //Components: nil, + }, + }) + if err != nil { + logger.Errorf("error sending interaction response: %s", err) + } + } +} + func slashCommandListener(event *events.SlashCommandEvent) { switch event.CommandName { case "eval": go func() { - start := time.Now() code := event.Option("code").String() embed := api.NewEmbedBuilder(). SetColor(orange). @@ -180,15 +204,14 @@ func slashCommandListener(event *events.SlashCommandEvent) { AddField("Time", "...", true). AddField("Code", "```go\n"+code+"\n```", false). AddField("Output", "```\n...\n```", false) + _ = event.Reply(api.NewCommandResponseBuilder().SetEmbeds(embed.Build()).Build()) - _ = event.Reply(api.NewInteractionResponseBuilder().SetEmbeds(embed.Build()).Build()) - - vars := map[string]interface{}{ + start := time.Now() + output, err := gval.Evaluate(code, map[string]interface{}{ "disgo": event.Disgo(), "dgo": event.Disgo(), "event": event, - } - output, err := gval.Evaluate(code, vars) + }) elapsed := time.Since(start) embed.SetField(1, "Time", strconv.Itoa(int(elapsed.Milliseconds()))+"ms", true) @@ -205,7 +228,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { ) return } - _, _ = event.EditOriginal(api.NewFollowupMessageBuilder(). + _, err = event.EditOriginal(api.NewFollowupMessageBuilder(). SetEmbeds(embed. SetColor(green). SetField(0, "Status", "Success", true). @@ -213,47 +236,56 @@ func slashCommandListener(event *events.SlashCommandEvent) { Build(), ). Build(), - ) + ); if err != nil { + logger.Errorf("error sending interaction response: %s", err) + } }() case "say": - _ = event.Reply(api.NewInteractionResponseBuilder(). + _ = event.Reply(api.NewCommandResponseBuilder(). SetContent(event.Option("message").String()). SetAllowedMentionsEmpty(). Build(), ) case "test": - _ = event.Reply(api.NewInteractionResponseBuilder(). + if err := event.Reply(api.NewCommandResponseBuilder(). SetEphemeral(true). - SetContent("followup 2 only you can see"). - SetComponents(&api.Buttons{ - Component: api.Component{ - Type: api.ComponentTypeButtons, - }, - Buttons: []*api.Button{ - { - Component: api.Component{ - Type: api.ComponentTypeButton, - }, - CustomID: "1", - Label: "test", + SetContent("test1"). + SetEmbeds(api.NewEmbedBuilder().SetDescription("this message should have some buttons").Build()). + SetComponents(api.NewRow( + api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewCustomEmoji("837665167780216852"), false), + api.NewSelect("select", "placeholder", 1, 2, + &api.SelectOption{ + Label: "test1", + Value: "value1", + Default: false, + Description: "value1", }, - }, - }). + &api.SelectOption{ + Label: "test2", + Value: "value2", + Default: false, + Description: "value2", + }, + ), + )). Build(), - ) + ); err != nil { + logger.Errorf("error sending interaction response: %s", err) + } case "addrole": user := event.Option("member").User() role := event.Option("role").Role() err := event.Disgo().RestClient().AddMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { - _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewCommandResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(green).SetDescriptionf("Added %s to %s", role, user).Build(), ).Build()) } else { - _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewCommandResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(red).SetDescriptionf("Failed to add %s to %s", role, user).Build(), ).Build()) } @@ -263,11 +295,11 @@ func slashCommandListener(event *events.SlashCommandEvent) { role := event.Option("role").Role() err := event.Disgo().RestClient().RemoveMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { - _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewCommandResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(65280).SetDescriptionf("Removed %s from %s", role, user).Build(), ).Build()) } else { - _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewCommandResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(16711680).SetDescriptionf("Failed to remove %s from %s", role, user).Build(), ).Build()) } diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index 47299c57..aaea9a86 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -17,16 +17,16 @@ func (h InteractionCreateHandler) Event() api.GatewayEventType { // New constructs a new payload receiver for the raw gateway event func (h InteractionCreateHandler) New() interface{} { - return &api.Interaction{} + return &api.FullInteraction{} } // HandleGatewayEvent handles the specific raw gateway event func (h InteractionCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - interaction, ok := i.(*api.FullInteraction) + fullInteraction, ok := i.(*api.FullInteraction) if !ok { return } - handleInteraction(disgo, eventManager, sequenceNumber, interaction, nil) + handleInteraction(disgo, eventManager, sequenceNumber, fullInteraction, nil) } func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, fullInteraction *api.FullInteraction, c chan *api.InteractionResponse) { @@ -87,5 +87,11 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN disgo.Logger().Errorf("failed to unmarshal ComponentInteractionData: %s", err) return } + eventManager.Dispatch(events.ButtonClickEvent{ + GenericInteractionEvent: genericInteractionEvent, + CustomID: data.CustomID, + ComponentType: data.Type, + Message: fullInteraction.Message, + }) } } From 1b385defe87bb9cb94431df4421339bcccddd4c6 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 1 May 2021 18:52:23 +0200 Subject: [PATCH 04/22] add button ack InteractionResponseType --- api/interaction_response.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/interaction_response.go b/api/interaction_response.go index efb45134..1bf8fc57 100644 --- a/api/interaction_response.go +++ b/api/interaction_response.go @@ -10,7 +10,7 @@ const ( _ InteractionResponseTypeChannelMessageWithSource InteractionResponseTypeDeferredChannelMessageWithSource - _ + InteractionResponseTypeButtonAck InteractionResponseTypeButtonResponse ) From 4b1c38ea2de3b200b58a313cc5dc30c249498181 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 1 May 2021 19:00:26 +0200 Subject: [PATCH 05/22] we should use the component interface here --- api/interaction_followup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/interaction_followup.go b/api/interaction_followup.go index 7fb1af43..4a8083d4 100644 --- a/api/interaction_followup.go +++ b/api/interaction_followup.go @@ -7,7 +7,7 @@ type FollowupMessage struct { Content *string `json:"content,omitempty"` TTS *bool `json:"tts,omitempty"` Embeds []*Embed `json:"embeds,omitempty"` - Components []interface{} `json:"components,omitempty"` + Components []Component `json:"components,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` Flags *MessageFlags `json:"flags,omitempty"` } From 189cb6e818c470e505870b787f1012bee789d365 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sat, 1 May 2021 19:02:35 +0200 Subject: [PATCH 06/22] and here too --- api/interaction_followup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/interaction_followup.go b/api/interaction_followup.go index 4a8083d4..8d5950d2 100644 --- a/api/interaction_followup.go +++ b/api/interaction_followup.go @@ -72,7 +72,7 @@ func (b *FollowupMessageBuilder) RemoveEmbed(index int) *FollowupMessageBuilder } // SetComponents sets the Component(s) of the FollowupMessage -func (b *FollowupMessageBuilder) SetComponents(components ...interface{}) *FollowupMessageBuilder { +func (b *FollowupMessageBuilder) SetComponents(components ...Component) *FollowupMessageBuilder { b.Components = components return b } From 1938bc3e86ae79e5e3e2ed96a4f826bd91487637 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 14 May 2021 21:54:48 +0200 Subject: [PATCH 07/22] complexer example --- example/examplebot.go | 68 ++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/example/examplebot.go b/example/examplebot.go index 272f750c..582909d1 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -180,11 +180,34 @@ func rawGatewayEventListener(event *events.RawGatewayEvent) { func buttonClickListener(event *events.ButtonClickEvent) { switch event.CustomID { case "test": + content := "test2" err := event.Reply(&api.InteractionResponse{ Type: api.InteractionResponseTypeButtonResponse, Data: &api.ButtonResponseData{ - Content: nil, - //Components: nil, + Content: &content, + Components: []api.Component{ + api.NewRow( + api.NewBlurpleButton("test2", "test2", api.NewEmoji("✔"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewCustomEmoji("837665167780216852"), false), + ), + }, + }, + }) + if err != nil { + logger.Errorf("error sending interaction response: %s", err) + } + case "test2": + content := "test" + err := event.Reply(&api.InteractionResponse{ + Type: api.InteractionResponseTypeButtonResponse, + Data: &api.ButtonResponseData{ + Content: &content, + Components: []api.Component{ + api.NewRow( + api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewCustomEmoji("837665167780216852"), false), + ), + }, }, }) if err != nil { @@ -236,7 +259,8 @@ func slashCommandListener(event *events.SlashCommandEvent) { Build(), ). Build(), - ); if err != nil { + ) + if err != nil { logger.Errorf("error sending interaction response: %s", err) } }() @@ -253,24 +277,28 @@ func slashCommandListener(event *events.SlashCommandEvent) { SetEphemeral(true). SetContent("test1"). SetEmbeds(api.NewEmbedBuilder().SetDescription("this message should have some buttons").Build()). - SetComponents(api.NewRow( - api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewCustomEmoji("837665167780216852"), false), - api.NewSelect("select", "placeholder", 1, 2, - &api.SelectOption{ - Label: "test1", - Value: "value1", - Default: false, - Description: "value1", - }, - &api.SelectOption{ - Label: "test2", - Value: "value2", - Default: false, - Description: "value2", - }, + SetComponents( + api.NewRow( + api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewCustomEmoji("837665167780216852"), false), ), - )). + /*api.NewRow( + api.NewSelect("select", "placeholder", 1, 2, + &api.SelectOption{ + Label: "test1", + Value: "value1", + Default: true, + Description: "value1", + }, + &api.SelectOption{ + Label: "test2", + Value: "value2", + Default: false, + Description: "value2", + }, + ), + ),*/ + ). Build(), ); err != nil { logger.Errorf("error sending interaction response: %s", err) From 68a8a9f27c4df8bd8037be4834222215e9e60895 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 16 May 2021 01:17:44 +0200 Subject: [PATCH 08/22] added animated to emoji struct --- api/component.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/component.go b/api/component.go index dc1bf8c6..d674aeef 100644 --- a/api/component.go +++ b/api/component.go @@ -39,6 +39,7 @@ func NewEmoji(name string) *Emoji { } type Emoji struct { - Name string `json:"name,omitempty"` - ID Snowflake `json:"id,omitempty"` + Name string `json:"name,omitempty"` + ID Snowflake `json:"id,omitempty"` + Animated bool `json:"animated"` } From 32ec14139d055b6df36f9b8d2cd36c0aec27c4cd Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 16 May 2021 01:22:46 +0200 Subject: [PATCH 09/22] hm maybe like this? --- api/component.go | 8 ++++++-- example/examplebot.go | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/api/component.go b/api/component.go index d674aeef..779d41f5 100644 --- a/api/component.go +++ b/api/component.go @@ -30,8 +30,12 @@ func (t ComponentImpl) Type() ComponentType { return t.ComponentType } -func NewCustomEmoji(emoteID Snowflake) *Emoji { - return &Emoji{ID: emoteID} +func NewEmote(emoteID Snowflake) *Emoji { + return &Emoji{ID: emoteID, Animated: false} +} + +func NewAnimatedEmote(emoteID Snowflake) *Emoji { + return &Emoji{ID: emoteID, Animated: true} } func NewEmoji(name string) *Emoji { diff --git a/example/examplebot.go b/example/examplebot.go index 582909d1..2ba2ee5c 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -188,7 +188,7 @@ func buttonClickListener(event *events.ButtonClickEvent) { Components: []api.Component{ api.NewRow( api.NewBlurpleButton("test2", "test2", api.NewEmoji("✔"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewCustomEmoji("837665167780216852"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("837665167780216852"), false), ), }, }, @@ -205,7 +205,7 @@ func buttonClickListener(event *events.ButtonClickEvent) { Components: []api.Component{ api.NewRow( api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewCustomEmoji("837665167780216852"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("837665167780216852"), false), ), }, }, @@ -280,7 +280,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { SetComponents( api.NewRow( api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewCustomEmoji("837665167780216852"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("837665167780216852"), false), ), /*api.NewRow( api.NewSelect("select", "placeholder", 1, 2, From 5b8ac82c55f214f5f73c88f3058b596e86f09ee4 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 16 May 2021 21:02:13 +0200 Subject: [PATCH 10/22] added more env vars wuhu --- example/examplebot.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/example/examplebot.go b/example/examplebot.go index 2ba2ee5c..8586d942 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -21,9 +21,10 @@ const red = 16711680 const orange = 16562691 const green = 65280 -const guildID = "817327181659111454" -const adminRoleID = "817327279583264788" -const testRoleID = "825156597935243304" +var guildID = api.Snowflake(os.Getenv("guild_id")) +var adminRoleID = api.Snowflake(os.Getenv("admin_role_id")) +var testRoleID = api.Snowflake(os.Getenv("test_role_id")) +var emoteID = api.Snowflake(os.Getenv("test_emote_id")) var logger = logrus.New() var client = http.DefaultClient @@ -188,7 +189,7 @@ func buttonClickListener(event *events.ButtonClickEvent) { Components: []api.Component{ api.NewRow( api.NewBlurpleButton("test2", "test2", api.NewEmoji("✔"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("837665167780216852"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote(emoteID), false), ), }, }, @@ -205,7 +206,7 @@ func buttonClickListener(event *events.ButtonClickEvent) { Components: []api.Component{ api.NewRow( api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("837665167780216852"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote(emoteID), false), ), }, }, @@ -280,7 +281,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { SetComponents( api.NewRow( api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("837665167780216852"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote(emoteID), false), ), /*api.NewRow( api.NewSelect("select", "placeholder", 1, 2, From 12b068c8ad1ce082261493a3c79f1c32f0409160 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Sun, 16 May 2021 23:59:01 +0200 Subject: [PATCH 11/22] fixed compile error --- api/events/interaction_events.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index ec63002a..db02c10c 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -126,11 +126,10 @@ func (e SlashCommandEvent) OptionsT(optionType api.CommandOptionType) []*api.Opt // Acknowledge replies to the api.Interaction with api.InteractionResponseTypeDeferredChannelMessageWithSource func (e *SlashCommandEvent) Acknowledge(ephemeral bool) error { - var data *api.InteractionResponseData + var data *api.CommandResponseData if ephemeral { - flag := api.MessageFlagEphemeral - data = &api.InteractionResponseData{ - Flags: &flag, + data = &api.CommandResponseData{ + Flags: api.MessageFlagEphemeral, } } return e.Reply(&api.InteractionResponse{ From c80a65bbeb909b49f32f8d4dd14c7f43be5b44c1 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Wed, 19 May 2021 19:03:14 +0200 Subject: [PATCH 12/22] updated example --- example/examplebot.go | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/example/examplebot.go b/example/examplebot.go index 8586d942..86a2bedb 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -283,22 +283,9 @@ func slashCommandListener(event *events.SlashCommandEvent) { api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote(emoteID), false), ), - /*api.NewRow( - api.NewSelect("select", "placeholder", 1, 2, - &api.SelectOption{ - Label: "test1", - Value: "value1", - Default: true, - Description: "value1", - }, - &api.SelectOption{ - Label: "test2", - Value: "value2", - Default: false, - Description: "value2", - }, - ), - ),*/ + api.NewRow( + api.NewBlurpleButton("test2", "test2", api.NewEmoji("✔"), false), + ), ). Build(), ); err != nil { From 9fc30b8d2a7f31bd16b9bf9f039dad5582e76336 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Wed, 26 May 2021 18:05:53 +0200 Subject: [PATCH 13/22] added impl check for WebhookServerImpl --- internal/webhook_server_impl.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/webhook_server_impl.go b/internal/webhook_server_impl.go index a522d1fb..fef8da2c 100644 --- a/internal/webhook_server_impl.go +++ b/internal/webhook_server_impl.go @@ -12,6 +12,8 @@ import ( "github.com/gorilla/mux" ) +var _ api.WebhookServer = (*WebhookServerImpl)(nil) + func newWebhookServerImpl(disgo api.Disgo, listenURL string, listenPort int, publicKey string) api.WebhookServer { hexDecodedKey, err := hex.DecodeString(publicKey) if err != nil { From 96215a744aeb13cae32d8a32aed6f233c70b6bb5 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 27 May 2021 01:41:38 +0200 Subject: [PATCH 14/22] refactored/reworked interaction stuff --- .github/dependabot.yml | 22 ++-- api/action_row.go | 13 ++ api/button.go | 97 ++++++-------- api/button_response.go | 8 +- api/command_response.go | 116 ----------------- api/component.go | 35 +---- api/emote.go | 20 ++- api/entity_builder.go | 5 +- api/events/interaction_events.go | 95 +++++++------- api/interaction.go | 61 +++++---- api/interaction_followup.go | 21 ++- api/message.go | 11 +- api/message_builder.go | 8 +- api/row.go | 15 --- api/select.go | 31 ----- api/slash_command_response.go | 121 ++++++++++++++++++ example/examplebot.go | 56 ++++---- internal/entity_builder_impl.go | 61 +++++---- .../handlers/interaction_create_handler.go | 46 +++---- 19 files changed, 399 insertions(+), 443 deletions(-) create mode 100644 api/action_row.go delete mode 100644 api/command_response.go delete mode 100644 api/row.go delete mode 100644 api/select.go create mode 100644 api/slash_command_response.go diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 32090e36..3cc9868f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,13 +1,13 @@ version: 2 updates: -- package-ecosystem: gomod - directory: "/" - schedule: - interval: daily - open-pull-requests-limit: 10 - target-branch: development -- package-ecosystem: gomod - directory: "/example" - schedule: - interval: daily - open-pull-requests-limit: 10 + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + target-branch: development + - package-ecosystem: gomod + directory: "/example" + schedule: + interval: daily + open-pull-requests-limit: 10 diff --git a/api/action_row.go b/api/action_row.go new file mode 100644 index 00000000..7e9fe4bd --- /dev/null +++ b/api/action_row.go @@ -0,0 +1,13 @@ +package api + +func NewActionRow(components ...Component) *ActionRow { + return &ActionRow{ + ComponentImpl: newComponentImpl(ComponentTypeActionRow), + Components: components, + } +} + +type ActionRow struct { + ComponentImpl + Components []Component `json:"components"` +} diff --git a/api/button.go b/api/button.go index ac33f552..2f7a1bc5 100644 --- a/api/button.go +++ b/api/button.go @@ -1,76 +1,53 @@ package api -func NewBlurpleButton(label string, customID string, emoji *Emoji, disabled bool) *Button { +type ButtonStyle int + +const ( + ButtonStylePrimary = iota + 1 + ButtonStyleSecondary + ButtonStyleSuccess + ButtonStyleDanger + ButtonStyleLink +) + +func NewButton(style ButtonStyle, label *string, customID *string, url *string, emoji *Emote, disabled *bool) *Button { return &Button{ - ComponentImpl: ComponentImpl{ - ComponentType: ComponentTypeButton, - }, - Style: StyleBlurple, - CustomID: customID, - Label: label, - Emoji: emoji, - Disabled: disabled, + ComponentImpl: newComponentImpl(ComponentTypeButton), + Style: style, + CustomID: customID, + URL: url, + Label: label, + Emoji: emoji, + Disabled: disabled, } } -func NewGreyButton(label string, customID string, emoji *Emoji, disabled bool) *Button { - return &Button{ - ComponentImpl: ComponentImpl{ - ComponentType: ComponentTypeButton, - }, - Style: StyleGrey, - CustomID: customID, - Label: label, - Emoji: emoji, - Disabled: disabled, - } +func NewPrimaryButton(label string, customID string, emoji *Emote, disabled bool) *Button { + return NewButton(ButtonStylePrimary, &label, &customID, nil, emoji, &disabled) } -func NewGreenButton(label string, customID string, emoji *Emoji, disabled bool) *Button { - return &Button{ - ComponentImpl: ComponentImpl{ - ComponentType: ComponentTypeButton, - }, - Style: StyleGreen, - CustomID: customID, - Label: label, - Emoji: emoji, - Disabled: disabled, - } +func NewSecondaryButton(label string, customID string, emoji *Emote, disabled bool) *Button { + return NewButton(ButtonStyleSecondary, &label, &customID, nil, emoji, &disabled) } -func NewRedButton(label string, customID string, emoji *Emoji, disabled bool) *Button { - return &Button{ - ComponentImpl: ComponentImpl{ - ComponentType: ComponentTypeButton, - }, - Style: StyleRed, - CustomID: customID, - Label: label, - Emoji: emoji, - Disabled: disabled, - } +func NewSuccessButton(label string, customID string, emoji *Emote, disabled bool) *Button { + return NewButton(ButtonStyleSuccess, &label, &customID, nil, emoji, &disabled) } -func NewLinkButton(label string, URL string, emoji *Emoji, disabled bool) *Button { - return &Button{ - ComponentImpl: ComponentImpl{ - ComponentType: ComponentTypeButton, - }, - Style: StyleHyperlink, - Label: label, - URL: URL, - Emoji: emoji, - Disabled: disabled, - } +func NewDangerButton(label string, customID string, emoji *Emote, disabled bool) *Button { + return NewButton(ButtonStyleDanger, &label, &customID, nil, emoji, &disabled) +} + +func NewLinkButton(label string, url string, emoji *Emote, disabled bool) *Button { + return NewButton(ButtonStyleLink, &label, nil, &url, emoji, &disabled) } type Button struct { ComponentImpl - Style Style `json:"style,omitempty"` - CustomID string `json:"custom_id,omitempty"` - Label string `json:"label,omitempty"` - URL string `json:"url,omitempty"` - Emoji *Emoji `json:"emoji,omitempty"` - Disabled bool `json:"disabled,omitempty"` -} \ No newline at end of file + Style ButtonStyle `json:"style,omitempty"` + Label *string `json:"label,omitempty"` + Emoji *Emote `json:"emoji,omitempty"` + CustomID *string `json:"custom_id,omitempty"` + URL *string `json:"url,omitempty"` + Disabled *bool `json:"disabled,omitempty"` +} diff --git a/api/button_response.go b/api/button_response.go index 8f591e03..90fd2a5d 100644 --- a/api/button_response.go +++ b/api/button_response.go @@ -8,7 +8,7 @@ type ButtonResponseData struct { Embeds []*Embed `json:"embeds,omitempty"` Components []Component `json:"components,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - Flags *MessageFlags `json:"flags,omitempty"` + Flags MessageFlags `json:"flags,omitempty"` } // ButtonResponseBuilder allows you to create an InteractionResponse with ease @@ -85,17 +85,17 @@ func (b *ButtonResponseBuilder) SetAllowedMentionsEmpty() *ButtonResponseBuilder // SetFlags sets the message flags of the InteractionResponse func (b *ButtonResponseBuilder) SetFlags(flags MessageFlags) *ButtonResponseBuilder { - b.Flags = &flags + b.Flags = flags return b } // SetEphemeral adds/removes MessageFlagEphemeral to the message flags func (b *ButtonResponseBuilder) SetEphemeral(ephemeral bool) *ButtonResponseBuilder { if ephemeral { - *b.Flags = MessageFlagEphemeral + b.Flags &= MessageFlagEphemeral } else { - *b.Flags |= MessageFlagEphemeral + b.Flags |= MessageFlagEphemeral } return b } diff --git a/api/command_response.go b/api/command_response.go deleted file mode 100644 index 10188ccb..00000000 --- a/api/command_response.go +++ /dev/null @@ -1,116 +0,0 @@ -package api - -import "fmt" - -// The CommandResponseData is used to specify the message_events options when creating an InteractionResponse -type CommandResponseData struct { - TTS *bool `json:"tts,omitempty"` - Content *string `json:"content,omitempty"` - Embeds []*Embed `json:"embeds,omitempty"` - Components []Component `json:"components,omitempty"` - AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - Flags MessageFlags `json:"flags,omitempty"` -} - -// CommandResponseBuilder allows you to create an InteractionResponse with ease -type CommandResponseBuilder struct { - CommandResponseData -} - -// NewCommandResponseBuilder returns a new CommandResponseBuilder -func NewCommandResponseBuilder() *CommandResponseBuilder { - return &CommandResponseBuilder{ - CommandResponseData: CommandResponseData{ - AllowedMentions: &DefaultInteractionAllowedMentions, - }, - } -} - -// SetTTS sets if the InteractionResponse is a tts message -func (b *CommandResponseBuilder) SetTTS(tts bool) *CommandResponseBuilder { - b.TTS = &tts - return b -} - -// SetContent sets the content of the InteractionResponse -func (b *CommandResponseBuilder) SetContent(content string) *CommandResponseBuilder { - b.Content = &content - return b -} - -// SetContentf sets the content of the InteractionResponse with format -func (b *CommandResponseBuilder) SetContentf(content string, a ...interface{}) *CommandResponseBuilder { - contentf := fmt.Sprintf(content, a...) - b.Content = &contentf - return b -} - -// SetEmbeds sets the embeds of the InteractionResponse -func (b *CommandResponseBuilder) SetEmbeds(embeds ...*Embed) *CommandResponseBuilder { - b.Embeds = embeds - return b -} - -// AddEmbeds adds multiple embeds to the InteractionResponse -func (b *CommandResponseBuilder) AddEmbeds(embeds ...*Embed) *CommandResponseBuilder { - b.Embeds = append(b.Embeds, embeds...) - return b -} - -// ClearEmbeds removes all of the embeds from the InteractionResponse -func (b *CommandResponseBuilder) ClearEmbeds() *CommandResponseBuilder { - if b != nil { - b.Embeds = []*Embed{} - } - return b -} - -// RemoveEmbed removes an embed from the InteractionResponse -func (b *CommandResponseBuilder) RemoveEmbed(i int) *CommandResponseBuilder { - if b != nil && len(b.Embeds) > i { - b.Embeds = append(b.Embeds[:i], b.Embeds[i+1:]...) - } - return b -} - -// SetComponents sets the Component(s) of the InteractionResponse -func (b *CommandResponseBuilder) SetComponents(components ...Component) *CommandResponseBuilder { - b.Components = components - return b -} - -// SetAllowedMentions sets the allowed mentions of the InteractionResponse -func (b *CommandResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *CommandResponseBuilder { - b.AllowedMentions = allowedMentions - return b -} - -// SetAllowedMentionsEmpty sets the allowed mentions of the InteractionResponse to nothing -func (b *CommandResponseBuilder) SetAllowedMentionsEmpty() *CommandResponseBuilder { - return b.SetAllowedMentions(&AllowedMentions{}) -} - -// SetFlags sets the message flags of the InteractionResponse -func (b *CommandResponseBuilder) SetFlags(flags MessageFlags) *CommandResponseBuilder { - b.Flags = flags - return b -} - -// SetEphemeral adds/removes MessageFlagEphemeral to the message flags -func (b *CommandResponseBuilder) SetEphemeral(ephemeral bool) *CommandResponseBuilder { - if ephemeral { - b.Flags = MessageFlagEphemeral - - } else { - b.Flags |= MessageFlagEphemeral - } - return b -} - -// Build returns your built InteractionResponse -func (b *CommandResponseBuilder) Build() *InteractionResponse { - return &InteractionResponse{ - Type: InteractionResponseTypeChannelMessageWithSource, - Data: &b.CommandResponseData, - } -} diff --git a/api/component.go b/api/component.go index 779d41f5..5df61ef8 100644 --- a/api/component.go +++ b/api/component.go @@ -3,25 +3,18 @@ package api type ComponentType int const ( - ComponentTypeButtons = iota + 1 + ComponentTypeActionRow = iota + 1 ComponentTypeButton - ComponentTypeSelect -) - -type Style int - -const ( - StyleBlurple = iota + 1 - StyleGrey - StyleGreen - StyleRed - StyleHyperlink ) type Component interface { Type() ComponentType } +func newComponentImpl(componentType ComponentType) ComponentImpl { + return ComponentImpl{ComponentType: componentType} +} + type ComponentImpl struct { ComponentType ComponentType `json:"type"` } @@ -29,21 +22,3 @@ type ComponentImpl struct { func (t ComponentImpl) Type() ComponentType { return t.ComponentType } - -func NewEmote(emoteID Snowflake) *Emoji { - return &Emoji{ID: emoteID, Animated: false} -} - -func NewAnimatedEmote(emoteID Snowflake) *Emoji { - return &Emoji{ID: emoteID, Animated: true} -} - -func NewEmoji(name string) *Emoji { - return &Emoji{Name: name} -} - -type Emoji struct { - Name string `json:"name,omitempty"` - ID Snowflake `json:"id,omitempty"` - Animated bool `json:"animated"` -} diff --git a/api/emote.go b/api/emote.go index 5df8157f..6b17f5c3 100644 --- a/api/emote.go +++ b/api/emote.go @@ -1,12 +1,24 @@ package api +func NewEmote(name string, emoteID Snowflake) *Emote { + return &Emote{Name: name, ID: emoteID, Animated: false} +} + +func NewAnimatedEmote(name string, emoteID Snowflake) *Emote { + return &Emote{Name: name, ID: emoteID, Animated: true} +} + +func NewEmoji(name string) *Emote { + return &Emote{Name: name} +} + // An Emote allows you to interact with custom emojis in discord. type Emote struct { Disgo Disgo - ID Snowflake - GuildID Snowflake - Name string - Animated bool + GuildID Snowflake `json:"guild_id,omitempty"` + Name string `json:"name,omitempty"` + ID Snowflake `json:"id,omitempty"` + Animated bool `json:"animated,omitempty"` } // Guild returns the Guild of the Emote from the Cache diff --git a/api/entity_builder.go b/api/entity_builder.go index ad95c3e0..329a3632 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -15,9 +15,8 @@ var ( type EntityBuilder interface { Disgo() Disgo - CreateInteraction(interaction *Interaction, updateCache CacheStrategy) *Interaction - CreateComponentInteraction(interactionData *ComponentInteractionData, updateCache CacheStrategy) *ComponentInteractionData - CreateApplicationCommandInteraction(interactionData *SlashCommandInteractionData, updateCache CacheStrategy) *SlashCommandInteractionData + CreateButtonInteraction(fullInteraction *FullInteraction, updateCache CacheStrategy) *ButtonInteraction + CreateSlashCommandInteraction(fullInteraction *FullInteraction, updateCache CacheStrategy) *SlashCommandInteraction CreateGlobalCommand(command *Command, updateCache CacheStrategy) *Command diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index 9db0e9b1..fbd6cc3c 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -9,7 +9,7 @@ import ( // GenericInteractionEvent generic api.Interaction event type GenericInteractionEvent struct { GenericEvent - Interaction *api.Interaction + Interaction *api.Interaction ResponseChannel chan *api.InteractionResponse FromWebhook bool Replied bool @@ -29,17 +29,50 @@ func (e *GenericInteractionEvent) Reply(response *api.InteractionResponse) error return e.Disgo().RestClient().SendInteractionResponse(e.Interaction.ID, e.Interaction.Token, response) } + +// EditOriginal edits the original api.InteractionResponse +func (e *GenericInteractionEvent) EditOriginal(followupMessage *api.FollowupMessage) (*api.Message, error) { + return e.Disgo().RestClient().EditInteractionResponse(e.Disgo().ApplicationID(), e.Interaction.Token, followupMessage) +} + +// DeleteOriginal deletes the original api.InteractionResponse +func (e *GenericInteractionEvent) DeleteOriginal() error { + return e.Disgo().RestClient().DeleteInteractionResponse(e.Disgo().ApplicationID(), e.Interaction.Token) +} + +// SendFollowup used to send a api.FollowupMessage to an api.Interaction +func (e *GenericInteractionEvent) SendFollowup(followupMessage *api.FollowupMessage) (*api.Message, error) { + return e.Disgo().RestClient().SendFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, followupMessage) +} + +// EditFollowup used to edit a api.FollowupMessage from an api.Interaction +func (e *GenericInteractionEvent) EditFollowup(messageID api.Snowflake, followupMessage *api.FollowupMessage) (*api.Message, error) { + return e.Disgo().RestClient().EditFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID, followupMessage) +} + +// DeleteFollowup used to delete a api.FollowupMessage from an api.Interaction +func (e *GenericInteractionEvent) DeleteFollowup(messageID api.Snowflake) error { + return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID) } // SlashCommandEvent indicates that a slash api.Command was ran in a api.Guild type SlashCommandEvent struct { GenericInteractionEvent - CommandID api.Snowflake - CommandName string - SubCommandName *string - SubCommandGroupName *string - Options []*api.Option - Resolved *api.Resolved + SlashCommandInteraction *api.SlashCommandInteraction + CommandID api.Snowflake + CommandName string + SubCommandName *string + SubCommandGroupName *string + Options []*api.Option +} + +// DeferReply replies to the api.SlashCommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource +func (e *SlashCommandEvent) DeferReply(ephemeral bool) error { + var data *api.SlashCommandResponse + if ephemeral { + data = &api.SlashCommandResponse{Flags: api.MessageFlagEphemeral} + } + return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredChannelMessageWithSource, Data: data}) } // CommandPath returns the api.Command path @@ -85,49 +118,23 @@ func (e SlashCommandEvent) OptionsT(optionType api.CommandOptionType) []*api.Opt return options } -// Acknowledge replies to the api.Interaction with api.InteractionResponseTypeDeferredChannelMessageWithSource -func (e *SlashCommandEvent) Acknowledge(ephemeral bool) error { - var data *api.CommandResponseData - if ephemeral { - data = &api.CommandResponseData{ - Flags: api.MessageFlagEphemeral, - } - } - return e.Reply(&api.InteractionResponse{ - Type: api.InteractionResponseTypeDeferredChannelMessageWithSource, - Data: data, - }) -} - - -// EditOriginal edits the original api.InteractionResponse -func (e *SlashCommandEvent) EditOriginal(followupMessage *api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().EditInteractionResponse(e.Disgo().ApplicationID(), e.Interaction.Token, followupMessage) -} - -// DeleteOriginal deletes the original api.InteractionResponse -func (e *SlashCommandEvent) DeleteOriginal() error { - return e.Disgo().RestClient().DeleteInteractionResponse(e.Disgo().ApplicationID(), e.Interaction.Token) +type ButtonClickEvent struct { + GenericInteractionEvent + ButtonInteraction *api.ButtonInteraction } -// SendFollowup used to send a api.FollowupMessage to an api.Interaction -func (e *SlashCommandEvent) SendFollowup(followupMessage *api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().SendFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, followupMessage) +func (e *ButtonClickEvent) Acknowledge() error { + return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeButtonAck}) } -// EditFollowup used to edit a api.FollowupMessage from an api.Interaction -func (e *SlashCommandEvent) EditFollowup(messageID api.Snowflake, followupMessage *api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().EditFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID, followupMessage) +func (e *ButtonClickEvent) CustomID() string { + return e.ButtonInteraction.Data.CustomID } -// DeleteFollowup used to delete a api.FollowupMessage from an api.Interaction -func (e *SlashCommandEvent) DeleteFollowup(messageID api.Snowflake) error { - return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID) +func (e *ButtonClickEvent) ComponentType() string { + return e.ButtonInteraction.Data.CustomID } -type ButtonClickEvent struct { - GenericInteractionEvent - CustomID string - ComponentType api.ComponentType - Message *api.Message +func (e *ButtonClickEvent) Message() *api.Message { + return e.ButtonInteraction.Message } diff --git a/api/interaction.go b/api/interaction.go index 946ad0bc..ef77cfcd 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -8,30 +8,10 @@ type InteractionType int // Constants for InteractionType const ( InteractionTypePing InteractionType = iota + 1 - InteractionTypeApplicationCommand + InteractionTypeSlashCommand InteractionTypeComponent ) -type FullInteraction struct { - *Interaction - Data json.RawMessage `json:"data,omitempty"` - Message *Message `json:"message,omitempty"` -} - -// An Interaction is the slash command object you receive when a user uses one of your commands -type Interaction struct { - Disgo Disgo - ID Snowflake `json:"id"` - Type InteractionType `json:"type"` - Data *InteractionData `json:"data,omitempty"` - GuildID *Snowflake `json:"guild_id,omitempty"` - ChannelID *Snowflake `json:"channel_id,omitempty"` - Member *Member `json:"member,omitempty"` - User *User `json:"User,omitempty"` - Token string `json:"token"` - Version int `json:"version"` -} - // Guild returns the api.Guild from the api.Cache func (i *Interaction) Guild() *Guild { if i.GuildID == nil { @@ -97,29 +77,54 @@ func (i *Interaction) DeleteFollowup(messageID Snowflake) error { return i.Disgo.RestClient().DeleteFollowupMessage(i.Disgo.ApplicationID(), i.Token, messageID) } -// InteractionData is the command data payload -type InteractionData struct { +type FullInteraction struct { ID Snowflake `json:"id"` Type InteractionType `json:"type"` GuildID *Snowflake `json:"guild_id,omitempty"` ChannelID *Snowflake `json:"channel_id,omitempty"` + Message *Message `json:"message,omitempty"` Member *Member `json:"member,omitempty"` User *User `json:"User,omitempty"` Token string `json:"token"` Version int `json:"version"` + Data json.RawMessage `json:"data,omitempty"` +} + +// An Interaction is the slash command object you receive when a user uses one of your commands +type Interaction struct { + Disgo Disgo + ID Snowflake `json:"id"` + Type InteractionType `json:"type"` + GuildID *Snowflake `json:"guild_id,omitempty"` + ChannelID *Snowflake `json:"channel_id,omitempty"` + Member *Member `json:"member,omitempty"` + User *User `json:"User,omitempty"` + Token string `json:"token"` + Version int `json:"version"` +} + +type ButtonInteraction struct { + *Interaction + Message *Message `json:"message,omitempty"` + Data *ButtonInteractionData `json:"data,omitempty"` +} + +type SlashCommandInteraction struct { + *Interaction + Data *SlashCommandInteractionData `json:"data,omitempty"` } -// ComponentInteractionData is the command data payload -type ComponentInteractionData struct { - CustomID string `json:"custom_id"` - Type ComponentType `json:"component_type"` +// ButtonInteractionData is the command data payload +type ButtonInteractionData struct { + CustomID string `json:"custom_id"` + ComponentType ComponentType `json:"component_type"` } // SlashCommandInteractionData is the command data payload type SlashCommandInteractionData struct { ID Snowflake `json:"id"` Name string `json:"name"` - Resolved *Resolved `json:"resolved"` + Resolved *Resolved `json:"resolved,omitempty"` Options []*OptionData `json:"options,omitempty"` } diff --git a/api/interaction_followup.go b/api/interaction_followup.go index a6d29af1..3bb418f3 100644 --- a/api/interaction_followup.go +++ b/api/interaction_followup.go @@ -4,10 +4,10 @@ import "fmt" // FollowupMessage is used to add additional messages to an Interaction after you've responded initially type FollowupMessage struct { - Content *string `json:"content,omitempty"` - TTS *bool `json:"tts,omitempty"` + TTS bool `json:"tts,omitempty"` + Content string `json:"content,omitempty"` Embeds []*Embed `json:"embeds,omitempty"` - Components []Component `json:"components,omitempty"` + Components []Component `json:"components,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` Flags MessageFlags `json:"flags,omitempty"` } @@ -28,20 +28,19 @@ func NewFollowupMessageBuilder() *FollowupMessageBuilder { // SetTTS sets if the FollowupMessage is a tts message func (b *FollowupMessageBuilder) SetTTS(tts bool) *FollowupMessageBuilder { - b.TTS = &tts + b.TTS = tts return b } // SetContent sets the content of the FollowupMessage func (b *FollowupMessageBuilder) SetContent(content string) *FollowupMessageBuilder { - b.Content = &content + b.Content = content return b } // SetContentf sets the content of the FollowupMessage with format func (b *FollowupMessageBuilder) SetContentf(content string, a ...interface{}) *FollowupMessageBuilder { - contentf := fmt.Sprintf(content, a...) - b.Content = &contentf + b.Content = fmt.Sprintf(content, a...) return b } @@ -97,13 +96,9 @@ func (b *FollowupMessageBuilder) SetFlags(flags MessageFlags) *FollowupMessageBu // SetEphemeral adds/removes MessageFlagEphemeral to the message flags func (b *FollowupMessageBuilder) SetEphemeral(ephemeral bool) *FollowupMessageBuilder { if ephemeral { - if !b.Flags.Has(MessageFlagEphemeral) { - b.Flags = b.Flags.Add(MessageFlagEphemeral) - } + b.Flags &= MessageFlagEphemeral } else { - if b.Flags.Has(MessageFlagEphemeral) { - b.Flags = b.Flags.Remove(MessageFlagEphemeral) - } + b.Flags |= MessageFlagEphemeral } return b } diff --git a/api/message.go b/api/message.go index bb8ee933..35d4c7c2 100644 --- a/api/message.go +++ b/api/message.go @@ -166,7 +166,7 @@ type Message struct { Attachments []*MessageAttachment `json:"attachments"` TTS bool `json:"tts"` Embeds []*Embed `json:"embeds,omitempty"` - Components []Component `json:"components,omitempty"` + Components []Component `json:"components,omitempty"` CreatedAt time.Time `json:"timestamp"` Mentions []interface{} `json:"mentions"` MentionEveryone bool `json:"mention_everyone"` @@ -266,7 +266,7 @@ type MessageReaction struct { // MessageUpdate is used to edit a Message type MessageUpdate struct { Content *string `json:"content,omitempty"` - Components []Component `json:"components,omitempty"` + Components []Component `json:"components,omitempty"` Embed *Embed `json:"embed,omitempty"` Flags *MessageFlags `json:"flags,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` @@ -274,9 +274,10 @@ type MessageUpdate struct { // MessageCreate is the struct to create a new Message with type MessageCreate struct { - Content *string `json:"content,omitempty"` - Components []Component `json:"components,omitempty"` - TTS *bool `json:"tts,omitempty"` + Nonce string `json:"nonce,omitempty"` + Content string `json:"content,omitempty"` + Components []Component `json:"components,omitempty"` + TTS bool `json:"tts,omitempty"` Embed *Embed `json:"embed,omitempty"` AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` MessageReference *MessageReference `json:"message_reference,omitempty"` diff --git a/api/message_builder.go b/api/message_builder.go index 950d9295..10a986a9 100644 --- a/api/message_builder.go +++ b/api/message_builder.go @@ -11,6 +11,7 @@ type MessageBuilder struct { func NewMessageBuilder() *MessageBuilder { return &MessageBuilder{ MessageCreate: MessageCreate{ + Nonce: "test nonce", AllowedMentions: &DefaultMessageAllowedMentions, }, } @@ -28,20 +29,19 @@ func NewMessageBuilderWithContent(content string) *MessageBuilder { // SetContent sets content of the Message func (b *MessageBuilder) SetContent(content string) *MessageBuilder { - b.Content = &content + b.Content = content return b } // SetContentf sets content of the Message func (b *MessageBuilder) SetContentf(content string, a ...interface{}) *MessageBuilder { - contentf := fmt.Sprintf(content, a...) - b.Content = &contentf + b.Content = fmt.Sprintf(content, a...) return b } // SetTTS sets the text to speech of the Message func (b *MessageBuilder) SetTTS(tts bool) *MessageBuilder { - b.TTS = &tts + b.TTS = tts return b } diff --git a/api/row.go b/api/row.go deleted file mode 100644 index eb15d802..00000000 --- a/api/row.go +++ /dev/null @@ -1,15 +0,0 @@ -package api - -func NewRow(components ...Component) *Row { - return &Row{ - ComponentImpl: ComponentImpl{ - ComponentType: ComponentTypeButtons, - }, - Components: components, - } -} - -type Row struct { - ComponentImpl - Components []Component `json:"components,omitempty"` -} diff --git a/api/select.go b/api/select.go deleted file mode 100644 index 8fc76100..00000000 --- a/api/select.go +++ /dev/null @@ -1,31 +0,0 @@ -package api - -func NewSelect(customID string, placeholder string, minValues int, maxValues int, options ...*SelectOption) *Select { - return &Select{ - ComponentImpl: ComponentImpl{ - ComponentType: ComponentTypeSelect, - }, - CustomID: customID, - Placeholder: placeholder, - Options: options, - MinValues: minValues, - MaxValues: maxValues, - } -} - -type Select struct { - ComponentImpl - CustomID string `json:"custom_id,omitempty"` - Placeholder string `json:"placeholder,omitempty"` - Options []*SelectOption `json:"options,omitempty"` - MinValues int `json:"min_values,omitempty"` - MaxValues int `json:"max_values,omitempty"` -} - -type SelectOption struct { - Label string `json:"label"` - Value interface{} `json:"value"` - Default bool `json:"default,omitempty"` - Description string `json:"description"` - Emoji *Emoji `json:"emoji,omitempty"` -} diff --git a/api/slash_command_response.go b/api/slash_command_response.go new file mode 100644 index 00000000..d41caf8c --- /dev/null +++ b/api/slash_command_response.go @@ -0,0 +1,121 @@ +package api + +import "fmt" + +// The SlashCommandResponse is used to specify the message_events options when creating an InteractionResponse +type SlashCommandResponse struct { + TTS bool `json:"tts,omitempty"` + Content string `json:"content,omitempty"` + Embeds []*Embed `json:"embeds,omitempty"` + Components []Component `json:"components,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + Flags MessageFlags `json:"flags,omitempty"` +} + +// SlashCommandResponseBuilder allows you to create an InteractionResponse with ease +type SlashCommandResponseBuilder struct { + SlashCommandResponse +} + +// NewSlashCommandResponseBuilder returns a new SlashCommandResponseBuilder +func NewSlashCommandResponseBuilder() *SlashCommandResponseBuilder { + return &SlashCommandResponseBuilder{ + SlashCommandResponse: SlashCommandResponse{ + AllowedMentions: &DefaultInteractionAllowedMentions, + }, + } +} + +// SetTTS sets if the InteractionResponse is a tts message +func (b *SlashCommandResponseBuilder) SetTTS(tts bool) *SlashCommandResponseBuilder { + b.TTS = tts + return b +} + +// SetContent sets the content of the InteractionResponse +func (b *SlashCommandResponseBuilder) SetContent(content string) *SlashCommandResponseBuilder { + b.Content = content + return b +} + +// SetContentf sets the content of the InteractionResponse with format +func (b *SlashCommandResponseBuilder) SetContentf(content string, a ...interface{}) *SlashCommandResponseBuilder { + b.Content = fmt.Sprintf(content, a...) + return b +} + +// SetEmbeds sets the embeds of the InteractionResponse +func (b *SlashCommandResponseBuilder) SetEmbeds(embeds ...*Embed) *SlashCommandResponseBuilder { + b.Embeds = embeds + return b +} + +// AddEmbeds adds multiple embeds to the InteractionResponse +func (b *SlashCommandResponseBuilder) AddEmbeds(embeds ...*Embed) *SlashCommandResponseBuilder { + b.Embeds = append(b.Embeds, embeds...) + return b +} + +// ClearEmbeds removes all of the embeds from the InteractionResponse +func (b *SlashCommandResponseBuilder) ClearEmbeds() *SlashCommandResponseBuilder { + if b != nil { + b.Embeds = []*Embed{} + } + return b +} + +// RemoveEmbed removes an embed from the InteractionResponse +func (b *SlashCommandResponseBuilder) RemoveEmbed(i int) *SlashCommandResponseBuilder { + if b != nil && len(b.Embeds) > i { + b.Embeds = append(b.Embeds[:i], b.Embeds[i+1:]...) + } + return b +} + +// SetComponents sets the Component(s) of the InteractionResponse +func (b *SlashCommandResponseBuilder) SetComponents(components ...Component) *SlashCommandResponseBuilder { + b.Components = components + return b +} + +// AddComponents adds the Component(s) to the InteractionResponse +func (b *SlashCommandResponseBuilder) AddComponents(components ...Component) *SlashCommandResponseBuilder { + b.Components = append(b.Components, components...) + return b +} + +// SetAllowedMentions sets the allowed mentions of the InteractionResponse +func (b *SlashCommandResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *SlashCommandResponseBuilder { + b.AllowedMentions = allowedMentions + return b +} + +// SetAllowedMentionsEmpty sets the allowed mentions of the InteractionResponse to nothing +func (b *SlashCommandResponseBuilder) SetAllowedMentionsEmpty() *SlashCommandResponseBuilder { + return b.SetAllowedMentions(&AllowedMentions{}) +} + +// SetFlags sets the message flags of the InteractionResponse +func (b *SlashCommandResponseBuilder) SetFlags(flags MessageFlags) *SlashCommandResponseBuilder { + b.Flags = flags + return b +} + +// SetEphemeral adds/removes MessageFlagEphemeral to the message flags +func (b *SlashCommandResponseBuilder) SetEphemeral(ephemeral bool) *SlashCommandResponseBuilder { + if ephemeral { + b.Flags &= MessageFlagEphemeral + + } else { + b.Flags |= MessageFlagEphemeral + } + return b +} + +// Build returns your built InteractionResponse +func (b *SlashCommandResponseBuilder) Build() *InteractionResponse { + return &InteractionResponse{ + Type: InteractionResponseTypeChannelMessageWithSource, + Data: &b.SlashCommandResponse, + } +} diff --git a/example/examplebot.go b/example/examplebot.go index 728d16de..55c6bf27 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -56,7 +56,7 @@ func main() { { Name: "eval", Description: "runs some go code", - DefaultPermission: ptrBool(false), + DefaultPermission: ptrBool(true), Options: []*api.CommandOption{ { Type: api.CommandOptionTypeString, @@ -69,12 +69,12 @@ func main() { { Name: "test", Description: "test test test test test test", - DefaultPermission: ptrBool(false), + DefaultPermission: ptrBool(true), }, { Name: "say", Description: "says what you say", - DefaultPermission: ptrBool(false), + DefaultPermission: ptrBool(true), Options: []*api.CommandOption{ { Type: api.CommandOptionTypeString, @@ -87,7 +87,7 @@ func main() { { Name: "addrole", Description: "This command adds a role to a member", - DefaultPermission: ptrBool(false), + DefaultPermission: ptrBool(true), Options: []*api.CommandOption{ { Type: api.CommandOptionTypeUser, @@ -106,7 +106,7 @@ func main() { { Name: "removerole", Description: "This command removes a role from a member", - DefaultPermission: ptrBool(false), + DefaultPermission: ptrBool(true), Options: []*api.CommandOption{ { Type: api.CommandOptionTypeUser, @@ -179,7 +179,7 @@ func rawGatewayEventListener(event *events.RawGatewayEvent) { } func buttonClickListener(event *events.ButtonClickEvent) { - switch event.CustomID { + switch event.CustomID() { case "test": content := "test2" err := event.Reply(&api.InteractionResponse{ @@ -187,9 +187,9 @@ func buttonClickListener(event *events.ButtonClickEvent) { Data: &api.ButtonResponseData{ Content: &content, Components: []api.Component{ - api.NewRow( - api.NewBlurpleButton("test2", "test2", api.NewEmoji("✔"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote(emoteID), false), + api.NewActionRow( + api.NewPrimaryButton("test2", "test2", api.NewEmoji("✔"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("kittybot", emoteID), false), ), }, }, @@ -204,9 +204,9 @@ func buttonClickListener(event *events.ButtonClickEvent) { Data: &api.ButtonResponseData{ Content: &content, Components: []api.Component{ - api.NewRow( - api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote(emoteID), false), + api.NewActionRow( + api.NewPrimaryButton("test", "test", api.NewEmoji("❌"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("kittybot", emoteID), false), ), }, }, @@ -228,7 +228,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { AddField("Time", "...", true). AddField("Code", "```go\n"+code+"\n```", false). AddField("Output", "```\n...\n```", false) - _ = event.Reply(api.NewCommandResponseBuilder().SetEmbeds(embed.Build()).Build()) + _ = event.Reply(api.NewSlashCommandResponseBuilder().SetEmbeds(embed.Build()).Build()) start := time.Now() output, err := gval.Evaluate(code, map[string]interface{}{ @@ -241,7 +241,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { embed.SetField(1, "Time", strconv.Itoa(int(elapsed.Milliseconds()))+"ms", true) if err != nil { - _, _ = event.Interaction.EditOriginal(api.NewFollowupMessageBuilder(). + _, err = event.Interaction.EditOriginal(api.NewFollowupMessageBuilder(). SetEmbeds(embed. SetColor(red). SetField(0, "Status", "Failed", true). @@ -250,9 +250,12 @@ func slashCommandListener(event *events.SlashCommandEvent) { ). Build(), ) + if err != nil { + logger.Errorf("error sending interaction response: %s", err) + } return } - _, _ = event.Interaction.EditOriginal(api.NewFollowupMessageBuilder(). + _, err = event.Interaction.EditOriginal(api.NewFollowupMessageBuilder(). SetEmbeds(embed. SetColor(green). SetField(0, "Status", "Success", true). @@ -267,24 +270,23 @@ func slashCommandListener(event *events.SlashCommandEvent) { }() case "say": - _ = event.Reply(api.NewCommandResponseBuilder(). + _ = event.Reply(api.NewSlashCommandResponseBuilder(). SetContent(event.Option("message").String()). SetAllowedMentionsEmpty(). Build(), ) case "test": - if err := event.Reply(api.NewCommandResponseBuilder(). - SetEphemeral(true). + if err := event.Reply(api.NewSlashCommandResponseBuilder(). SetContent("test1"). SetEmbeds(api.NewEmbedBuilder().SetDescription("this message should have some buttons").Build()). SetComponents( - api.NewRow( - api.NewBlurpleButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote(emoteID), false), + api.NewActionRow( + api.NewPrimaryButton("test", "test", api.NewEmoji("❌"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("kittybot", emoteID), false), ), - api.NewRow( - api.NewBlurpleButton("test2", "test2", api.NewEmoji("✔"), false), + api.NewActionRow( + api.NewPrimaryButton("test2", "test2", api.NewEmoji("✔"), false), ), ). Build(), @@ -297,11 +299,11 @@ func slashCommandListener(event *events.SlashCommandEvent) { role := event.Option("role").Role() err := event.Disgo().RestClient().AddMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { - _ = event.Reply(api.NewCommandResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewSlashCommandResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(green).SetDescriptionf("Added %s to %s", role, user).Build(), ).Build()) } else { - _ = event.Reply(api.NewCommandResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewSlashCommandResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(red).SetDescriptionf("Failed to add %s to %s", role, user).Build(), ).Build()) } @@ -311,11 +313,11 @@ func slashCommandListener(event *events.SlashCommandEvent) { role := event.Option("role").Role() err := event.Disgo().RestClient().RemoveMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { - _ = event.Reply(api.NewCommandResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewSlashCommandResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(65280).SetDescriptionf("Removed %s from %s", role, user).Build(), ).Build()) } else { - _ = event.Reply(api.NewCommandResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewSlashCommandResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(16711680).SetDescriptionf("Failed to remove %s from %s", role, user).Build(), ).Build()) } diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 5a648f5d..959fa3c7 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -1,6 +1,8 @@ package internal import ( + "encoding/json" + "github.com/DisgoOrg/disgo/api" ) @@ -18,23 +20,45 @@ func (b *EntityBuilderImpl) Disgo() api.Disgo { return b.disgo } -// CreateInteraction returns a new api.Interaction entity -func (b EntityBuilderImpl) CreateInteraction(interaction *api.Interaction, updateCache api.CacheStrategy) *api.Interaction { - interaction.Disgo = b.disgo - if interaction.Member != nil { - interaction.Member = b.CreateMember(*interaction.GuildID, interaction.Member, api.CacheStrategyYes) +func (b EntityBuilderImpl) createInteraction(fullInteraction *api.FullInteraction, updateCache api.CacheStrategy) *api.Interaction { + interaction := &api.Interaction{ + Disgo: b.disgo, + ID: fullInteraction.ID, + Type: fullInteraction.Type, + GuildID: fullInteraction.GuildID, + ChannelID: fullInteraction.ChannelID, + Token: fullInteraction.Token, + Version: fullInteraction.Version, + } + + if fullInteraction.Member != nil { + interaction.Member = b.CreateMember(*fullInteraction.GuildID, fullInteraction.Member, api.CacheStrategyYes) } - if interaction.User != nil { - interaction.User = b.CreateUser(interaction.User, updateCache) + if fullInteraction.User != nil { + interaction.User = b.CreateUser(fullInteraction.User, updateCache) } -func (b *EntityBuilderImpl) CreateComponentInteraction(interactionData *api.ComponentInteractionData, updateCache api.CacheStrategy) *api.ComponentInteractionData { + return interaction +} + +// CreateButtonInteraction creates a api.ButtonInteraction from the full interaction response +func (b *EntityBuilderImpl) CreateButtonInteraction(fullInteraction *api.FullInteraction, updateCache api.CacheStrategy) *api.ButtonInteraction { + var data *api.ButtonInteractionData + _ = json.Unmarshal(fullInteraction.Data, &data) - return interactionData + return &api.ButtonInteraction{ + Interaction: b.createInteraction(fullInteraction, updateCache), + Message: b.CreateMessage(fullInteraction.Message, updateCache), + Data: data, + } } -func (b *EntityBuilderImpl) CreateApplicationCommandInteraction(interactionData *api.SlashCommandInteractionData, updateCache api.CacheStrategy) *api.SlashCommandInteractionData { - if interactionData.Resolved != nil { - resolved := interactionData.Resolved +// CreateSlashCommandInteraction creates a api.SlashCommandInteraction from the full interaction response +func (b *EntityBuilderImpl) CreateSlashCommandInteraction(fullInteraction *api.FullInteraction, updateCache api.CacheStrategy) *api.SlashCommandInteraction { + var data *api.SlashCommandInteractionData + _ = json.Unmarshal(fullInteraction.Data, &data) + + if data.Resolved != nil { + resolved := data.Resolved if resolved.Users != nil { for _, user := range resolved.Users { user = b.CreateUser(user, updateCache) @@ -59,18 +83,11 @@ func (b *EntityBuilderImpl) CreateApplicationCommandInteraction(interactionData } }*/ } - return interactionData -} -// CreateInteraction returns a new api.Interaction entity -func (b *EntityBuilderImpl) CreateInteraction(interaction *api.Interaction, updateCache api.CacheStrategy) *api.Interaction { - if interaction.Member != nil { - interaction.Member = b.CreateMember(*interaction.GuildID, interaction.Member, api.CacheStrategyYes) + return &api.SlashCommandInteraction{ + Interaction: b.createInteraction(fullInteraction, updateCache), + Data: data, } - if interaction.User != nil { - interaction.User = b.CreateUser(interaction.User, updateCache) - } - return interaction } // CreateGlobalCommand returns a new api.Command entity diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index aaea9a86..0d3cea37 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -1,8 +1,6 @@ package handlers import ( - "encoding/json" - "github.com/DisgoOrg/disgo/api" "github.com/DisgoOrg/disgo/api/events" ) @@ -30,29 +28,25 @@ func (h InteractionCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManag } func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, fullInteraction *api.FullInteraction, c chan *api.InteractionResponse) { - - interaction := disgo.EntityBuilder().CreateInteraction(fullInteraction.Interaction, api.CacheStrategyYes) genericInteractionEvent := events.GenericInteractionEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), - Interaction: interaction, ResponseChannel: c, FromWebhook: c != nil, Replied: false, } - eventManager.Dispatch(genericInteractionEvent) - switch interaction.Type { - case api.InteractionTypeApplicationCommand: - var data *api.SlashCommandInteractionData - if err := json.Unmarshal(fullInteraction.Data, &data); err != nil { - disgo.Logger().Errorf("failed to unmarshal SlashCommandInteractionData: %s", err) - return - } - options := data.Options + switch fullInteraction.Type { + case api.InteractionTypeSlashCommand: + interaction := disgo.EntityBuilder().CreateSlashCommandInteraction(fullInteraction, api.CacheStrategyYes) + + genericInteractionEvent.Interaction = interaction.Interaction + eventManager.Dispatch(genericInteractionEvent) + + options := interaction.Data.Options var subCommandName *string var subCommandGroupName *string if len(options) == 1 { - option := data.Options[0] + option := options[0] if option.Type == api.CommandOptionTypeSubCommandGroup { subCommandGroupName = &option.Name options = option.Options @@ -63,10 +57,11 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN options = option.Options } } + var newOptions []*api.Option for _, optionData := range options { newOptions = append(newOptions, &api.Option{ - Resolved: data.Resolved, + Resolved: interaction.Data.Resolved, Name: optionData.Name, Type: optionData.Type, Value: optionData.Value, @@ -75,23 +70,22 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN eventManager.Dispatch(events.SlashCommandEvent{ GenericInteractionEvent: genericInteractionEvent, - CommandID: data.ID, - CommandName: data.Name, + SlashCommandInteraction: interaction, + CommandID: interaction.Data.ID, + CommandName: interaction.Data.Name, SubCommandName: subCommandName, SubCommandGroupName: subCommandGroupName, Options: newOptions, }) case api.InteractionTypeComponent: - var data *api.ComponentInteractionData - if err := json.Unmarshal(fullInteraction.Data, &data); err != nil { - disgo.Logger().Errorf("failed to unmarshal ComponentInteractionData: %s", err) - return - } + interaction := disgo.EntityBuilder().CreateButtonInteraction(fullInteraction, api.CacheStrategyYes) + + genericInteractionEvent.Interaction = interaction.Interaction + eventManager.Dispatch(genericInteractionEvent) + eventManager.Dispatch(events.ButtonClickEvent{ GenericInteractionEvent: genericInteractionEvent, - CustomID: data.CustomID, - ComponentType: data.Type, - Message: fullInteraction.Message, + ButtonInteraction: interaction, }) } } From 1117a4d521c54831e3fe9c63ef3777c4f11dc9e2 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 27 May 2021 19:16:37 +0200 Subject: [PATCH 15/22] refactored button, message & slash commands stuff --- api/button.go | 32 ++-- api/button_response.go | 109 ------------ api/component.go | 11 ++ api/entity_builder.go | 2 +- api/events/interaction_events.go | 16 +- api/interaction.go | 20 +-- api/interaction_followup.go | 25 ++- api/interaction_response.go | 180 +++++++++++++++++++- api/message.go | 18 +- api/message_builder.go | 51 ++++++ api/slash_command_response.go | 121 ------------- example/examplebot.go | 63 +++---- internal/entity_builder_impl.go | 47 ++++- internal/handlers/all_handlers.go | 2 + internal/handlers/message_create_handler.go | 9 +- internal/handlers/message_delete_handler.go | 28 +++ internal/handlers/message_update_handler.go | 20 +++ internal/restclient_impl.go | 15 +- 18 files changed, 439 insertions(+), 330 deletions(-) delete mode 100644 api/button_response.go delete mode 100644 api/slash_command_response.go diff --git a/api/button.go b/api/button.go index 2f7a1bc5..827df4c2 100644 --- a/api/button.go +++ b/api/button.go @@ -10,44 +10,44 @@ const ( ButtonStyleLink ) -func NewButton(style ButtonStyle, label *string, customID *string, url *string, emoji *Emote, disabled *bool) *Button { +func NewButton(style ButtonStyle, label *string, customID string, url string, emote *Emote, disabled bool) *Button { return &Button{ ComponentImpl: newComponentImpl(ComponentTypeButton), Style: style, CustomID: customID, URL: url, Label: label, - Emoji: emoji, + Emote: emote, Disabled: disabled, } } -func NewPrimaryButton(label string, customID string, emoji *Emote, disabled bool) *Button { - return NewButton(ButtonStylePrimary, &label, &customID, nil, emoji, &disabled) +func NewPrimaryButton(label string, customID string, emote *Emote, disabled bool) *Button { + return NewButton(ButtonStylePrimary, &label, customID, "", emote, disabled) } -func NewSecondaryButton(label string, customID string, emoji *Emote, disabled bool) *Button { - return NewButton(ButtonStyleSecondary, &label, &customID, nil, emoji, &disabled) +func NewSecondaryButton(label string, customID string, emote *Emote, disabled bool) *Button { + return NewButton(ButtonStyleSecondary, &label, customID, "", emote, disabled) } -func NewSuccessButton(label string, customID string, emoji *Emote, disabled bool) *Button { - return NewButton(ButtonStyleSuccess, &label, &customID, nil, emoji, &disabled) +func NewSuccessButton(label string, customID string, emote *Emote, disabled bool) *Button { + return NewButton(ButtonStyleSuccess, &label, customID, "", emote, disabled) } -func NewDangerButton(label string, customID string, emoji *Emote, disabled bool) *Button { - return NewButton(ButtonStyleDanger, &label, &customID, nil, emoji, &disabled) +func NewDangerButton(label string, customID string, emote *Emote, disabled bool) *Button { + return NewButton(ButtonStyleDanger, &label, customID, "", emote, disabled) } -func NewLinkButton(label string, url string, emoji *Emote, disabled bool) *Button { - return NewButton(ButtonStyleLink, &label, nil, &url, emoji, &disabled) +func NewLinkButton(label string, url string, emote *Emote, disabled bool) *Button { + return NewButton(ButtonStyleLink, &label, "", url, emote, disabled) } type Button struct { ComponentImpl Style ButtonStyle `json:"style,omitempty"` Label *string `json:"label,omitempty"` - Emoji *Emote `json:"emoji,omitempty"` - CustomID *string `json:"custom_id,omitempty"` - URL *string `json:"url,omitempty"` - Disabled *bool `json:"disabled,omitempty"` + Emote *Emote `json:"emoji,omitempty"` + CustomID string `json:"custom_id,omitempty"` + URL string `json:"url,omitempty"` + Disabled bool `json:"disabled,omitempty"` } diff --git a/api/button_response.go b/api/button_response.go deleted file mode 100644 index 90fd2a5d..00000000 --- a/api/button_response.go +++ /dev/null @@ -1,109 +0,0 @@ -package api - -import "fmt" - -// The ButtonResponseData ... -type ButtonResponseData struct { - Content *string `json:"content"` - Embeds []*Embed `json:"embeds,omitempty"` - Components []Component `json:"components,omitempty"` - AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - Flags MessageFlags `json:"flags,omitempty"` -} - -// ButtonResponseBuilder allows you to create an InteractionResponse with ease -type ButtonResponseBuilder struct { - ButtonResponseData -} - -// NewButtonResponseBuilder returns a new ButtonResponseBuilder -func NewButtonResponseBuilder() *ButtonResponseBuilder { - return &ButtonResponseBuilder{ - ButtonResponseData: ButtonResponseData{ - AllowedMentions: &DefaultInteractionAllowedMentions, - }, - } -} - -// SetContent sets the content of the InteractionResponse -func (b *ButtonResponseBuilder) SetContent(content string) *ButtonResponseBuilder { - b.Content = &content - return b -} - -// SetContentf sets the content of the InteractionResponse with format -func (b *ButtonResponseBuilder) SetContentf(content string, a ...interface{}) *ButtonResponseBuilder { - contentf := fmt.Sprintf(content, a...) - b.Content = &contentf - return b -} - -// SetEmbeds sets the embeds of the InteractionResponse -func (b *ButtonResponseBuilder) SetEmbeds(embeds ...*Embed) *ButtonResponseBuilder { - b.Embeds = embeds - return b -} - -// AddEmbeds adds multiple embeds to the InteractionResponse -func (b *ButtonResponseBuilder) AddEmbeds(embeds ...*Embed) *ButtonResponseBuilder { - b.Embeds = append(b.Embeds, embeds...) - return b -} - -// ClearEmbeds removes all of the embeds from the InteractionResponse -func (b *ButtonResponseBuilder) ClearEmbeds() *ButtonResponseBuilder { - if b != nil { - b.Embeds = []*Embed{} - } - return b -} - -// RemoveEmbed removes an embed from the InteractionResponse -func (b *ButtonResponseBuilder) RemoveEmbed(i int) *ButtonResponseBuilder { - if b != nil && len(b.Embeds) > i { - b.Embeds = append(b.Embeds[:i], b.Embeds[i+1:]...) - } - return b -} - -// SetComponents sets the Component(s) of the InteractionResponse -func (b *ButtonResponseBuilder) SetComponents(components ...Component) *ButtonResponseBuilder { - b.Components = components - return b -} - -// SetAllowedMentions sets the allowed mentions of the InteractionResponse -func (b *ButtonResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *ButtonResponseBuilder { - b.AllowedMentions = allowedMentions - return b -} - -// SetAllowedMentionsEmpty sets the allowed mentions of the InteractionResponse to nothing -func (b *ButtonResponseBuilder) SetAllowedMentionsEmpty() *ButtonResponseBuilder { - return b.SetAllowedMentions(&AllowedMentions{}) -} - -// SetFlags sets the message flags of the InteractionResponse -func (b *ButtonResponseBuilder) SetFlags(flags MessageFlags) *ButtonResponseBuilder { - b.Flags = flags - return b -} - -// SetEphemeral adds/removes MessageFlagEphemeral to the message flags -func (b *ButtonResponseBuilder) SetEphemeral(ephemeral bool) *ButtonResponseBuilder { - if ephemeral { - b.Flags &= MessageFlagEphemeral - - } else { - b.Flags |= MessageFlagEphemeral - } - return b -} - -// Build returns your built InteractionResponse -func (b *ButtonResponseBuilder) Build() *InteractionResponse { - return &InteractionResponse{ - Type: InteractionResponseTypeButtonResponse, - Data: &b.ButtonResponseData, - } -} diff --git a/api/component.go b/api/component.go index 5df61ef8..6c734154 100644 --- a/api/component.go +++ b/api/component.go @@ -22,3 +22,14 @@ type ComponentImpl struct { func (t ComponentImpl) Type() ComponentType { return t.ComponentType } + +type UnmarshalComponent struct { + ComponentType ComponentType `json:"type"` + Style ButtonStyle `json:"style"` + Label *string `json:"label"` + Emote *Emote `json:"emoji"` + CustomID string `json:"custom_id"` + URL string `json:"url"` + Disabled bool `json:"disabled"` + Components []*UnmarshalComponent `json:"components"` +} diff --git a/api/entity_builder.go b/api/entity_builder.go index 329a3632..82776cc4 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -22,7 +22,7 @@ type EntityBuilder interface { CreateUser(user *User, updateCache CacheStrategy) *User - CreateMessage(message *Message, updateCache CacheStrategy) *Message + CreateMessage(message *FullMessage, updateCache CacheStrategy) *Message CreateGuild(guild *Guild, updateCache CacheStrategy) *Guild CreateMember(guildID Snowflake, member *Member, updateCache CacheStrategy) *Member diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index fbd6cc3c..f8a69f64 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -68,13 +68,17 @@ type SlashCommandEvent struct { // DeferReply replies to the api.SlashCommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource func (e *SlashCommandEvent) DeferReply(ephemeral bool) error { - var data *api.SlashCommandResponse + var data *api.InteractionResponseData if ephemeral { - data = &api.SlashCommandResponse{Flags: api.MessageFlagEphemeral} + data = &api.InteractionResponseData{Flags: api.MessageFlagEphemeral} } return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredChannelMessageWithSource, Data: data}) } +func (e *SlashCommandEvent) ReplyCreate(data *api.InteractionResponseData) error { + return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeChannelMessageWithSource, Data: data}) +} + // CommandPath returns the api.Command path func (e SlashCommandEvent) CommandPath() string { path := e.CommandName @@ -123,8 +127,12 @@ type ButtonClickEvent struct { ButtonInteraction *api.ButtonInteraction } -func (e *ButtonClickEvent) Acknowledge() error { - return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeButtonAck}) +func (e *ButtonClickEvent) DeferEdit() error { + return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredUpdateMessage}) +} + +func (e *ButtonClickEvent) ReplyEdit(data *api.InteractionResponseData) error { + return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeUpdateMessage, Data: data}) } func (e *ButtonClickEvent) CustomID() string { diff --git a/api/interaction.go b/api/interaction.go index ef77cfcd..589f15cd 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -78,16 +78,16 @@ func (i *Interaction) DeleteFollowup(messageID Snowflake) error { } type FullInteraction struct { - ID Snowflake `json:"id"` - Type InteractionType `json:"type"` - GuildID *Snowflake `json:"guild_id,omitempty"` - ChannelID *Snowflake `json:"channel_id,omitempty"` - Message *Message `json:"message,omitempty"` - Member *Member `json:"member,omitempty"` - User *User `json:"User,omitempty"` - Token string `json:"token"` - Version int `json:"version"` - Data json.RawMessage `json:"data,omitempty"` + ID Snowflake `json:"id"` + Type InteractionType `json:"type"` + GuildID *Snowflake `json:"guild_id,omitempty"` + ChannelID *Snowflake `json:"channel_id,omitempty"` + FullMessage *FullMessage `json:"message,omitempty"` + Member *Member `json:"member,omitempty"` + User *User `json:"User,omitempty"` + Token string `json:"token"` + Version int `json:"version"` + Data json.RawMessage `json:"data,omitempty"` } // An Interaction is the slash command object you receive when a user uses one of your commands diff --git a/api/interaction_followup.go b/api/interaction_followup.go index 3bb418f3..6c4462da 100644 --- a/api/interaction_followup.go +++ b/api/interaction_followup.go @@ -20,12 +20,29 @@ type FollowupMessageBuilder struct { // NewFollowupMessageBuilder returns a new FollowupMessageBuilder func NewFollowupMessageBuilder() *FollowupMessageBuilder { return &FollowupMessageBuilder{ - FollowupMessage{ + FollowupMessage: FollowupMessage{ AllowedMentions: &DefaultInteractionAllowedMentions, }, } } +// NewFollowupMessageBuilderByMessage returns a new FollowupMessageBuilder and takes an existing Message +func NewFollowupMessageBuilderByMessage(message *Message) *FollowupMessageBuilder { + msg := FollowupMessage{ + TTS: message.TTS, + Embeds: message.Embeds, + Components: message.Components, + AllowedMentions: &DefaultInteractionAllowedMentions, + Flags: message.Flags, + } + if message.Content != nil { + msg.Content = *message.Content + } + return &FollowupMessageBuilder{ + FollowupMessage: msg, + } +} + // SetTTS sets if the FollowupMessage is a tts message func (b *FollowupMessageBuilder) SetTTS(tts bool) *FollowupMessageBuilder { b.TTS = tts @@ -76,6 +93,12 @@ func (b *FollowupMessageBuilder) SetComponents(components ...Component) *Followu return b } +// AddComponents adds the Component(s) to the FollowupMessage +func (b *FollowupMessageBuilder) AddComponents(components ...Component) *FollowupMessageBuilder { + b.Components = append(b.Components, components...) + return b +} + // SetAllowedMentions sets the allowed mentions of the FollowupMessage func (b *FollowupMessageBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *FollowupMessageBuilder { b.AllowedMentions = allowedMentions diff --git a/api/interaction_response.go b/api/interaction_response.go index 1bf8fc57..65a214d6 100644 --- a/api/interaction_response.go +++ b/api/interaction_response.go @@ -1,5 +1,7 @@ package api +import "fmt" + // InteractionResponseType indicates the type of slash command response, whether it's responding immediately or deferring to edit your response later type InteractionResponseType int @@ -10,12 +12,182 @@ const ( _ InteractionResponseTypeChannelMessageWithSource InteractionResponseTypeDeferredChannelMessageWithSource - InteractionResponseTypeButtonAck - InteractionResponseTypeButtonResponse + InteractionResponseTypeDeferredUpdateMessage + InteractionResponseTypeUpdateMessage ) // InteractionResponse is how you answer interactions. If an answer is not sent within 3 seconds of receiving it, the interaction is failed, and you will be unable to respond to it. type InteractionResponse struct { - Type InteractionResponseType `json:"type"` - Data interface{} `json:"data,omitempty"` + Type InteractionResponseType `json:"type"` + Data *InteractionResponseData `json:"data,omitempty"` +} + +// The InteractionResponseData is used to specify the message_events options when creating an InteractionResponse +type InteractionResponseData struct { + TTS bool `json:"tts,omitempty"` + Content *string `json:"content,omitempty"` + Embeds []*Embed `json:"embeds,omitempty"` + Components []Component `json:"components,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + Flags MessageFlags `json:"flags,omitempty"` +} + +// InteractionResponseBuilder allows you to create an InteractionResponse with ease +type InteractionResponseBuilder struct { + InteractionResponse +} + +// NewInteractionResponseBuilder returns a new InteractionResponseBuilder +func NewInteractionResponseBuilder() *InteractionResponseBuilder { + return &InteractionResponseBuilder{ + InteractionResponse: InteractionResponse{ + Data: &InteractionResponseData{ + AllowedMentions: &DefaultInteractionAllowedMentions, + }, + }, + } +} + +// NewInteractionResponseBuilderByMessage returns a new InteractionResponseBuilder and takes an existing Message +func NewInteractionResponseBuilderByMessage(message *Message) *InteractionResponseBuilder { + rs := &InteractionResponseData{ + TTS: message.TTS, + Embeds: message.Embeds, + Components: message.Components, + AllowedMentions: &DefaultInteractionAllowedMentions, + Flags: message.Flags, + } + if message.Content != nil { + rs.Content = message.Content + } + return &InteractionResponseBuilder{ + InteractionResponse: InteractionResponse{ + Data: rs, + }, + } +} + +// SetType sets if the InteractionResponseType of this InteractionResponse +func (b *InteractionResponseBuilder) SetType(responseType InteractionResponseType) *InteractionResponseBuilder { + b.Type = responseType + return b +} + +// SetTTS sets if the InteractionResponse is a tts message +func (b *InteractionResponseBuilder) SetTTS(tts bool) *InteractionResponseBuilder { + b.Data.TTS = tts + return b +} + +// SetContent sets the content of the InteractionResponse +func (b *InteractionResponseBuilder) SetContent(content string) *InteractionResponseBuilder { + b.Data.Content = &content + return b +} + +// SetContentf sets the content of the InteractionResponse with format +func (b *InteractionResponseBuilder) SetContentf(content string, a ...interface{}) *InteractionResponseBuilder { + contentf := fmt.Sprintf(content, a...) + b.Data.Content = &contentf + return b +} + +// ClearContent sets the content of the InteractionResponse to nil +func (b *InteractionResponseBuilder) ClearContent() *InteractionResponseBuilder { + b.Data.Content = nil + return b +} + +// SetEmbeds sets the embeds of the InteractionResponse +func (b *InteractionResponseBuilder) SetEmbeds(embeds ...*Embed) *InteractionResponseBuilder { + b.Data.Embeds = embeds + return b +} + +// AddEmbeds adds multiple embeds to the InteractionResponse +func (b *InteractionResponseBuilder) AddEmbeds(embeds ...*Embed) *InteractionResponseBuilder { + b.Data.Embeds = append(b.Data.Embeds, embeds...) + return b +} + +// ClearEmbeds removes all of the embeds from the InteractionResponse +func (b *InteractionResponseBuilder) ClearEmbeds() *InteractionResponseBuilder { + if b != nil { + b.Data.Embeds = []*Embed{} + } + return b +} + +// RemoveEmbed removes an embed from the InteractionResponse +func (b *InteractionResponseBuilder) RemoveEmbed(i int) *InteractionResponseBuilder { + if b != nil && len(b.Data.Embeds) > i { + b.Data.Embeds = append(b.Data.Embeds[:i], b.Data.Embeds[i+1:]...) + } + return b +} + +// SetComponents sets the Component(s) of the InteractionResponse +func (b *InteractionResponseBuilder) SetComponents(components ...Component) *InteractionResponseBuilder { + b.Data.Components = components + return b +} + +// AddComponents adds the Component(s) to the InteractionResponse +func (b *InteractionResponseBuilder) AddComponents(components ...Component) *InteractionResponseBuilder { + b.Data.Components = append(b.Data.Components, components...) + return b +} + +// ClearComponents removes all of the Component(s) of the InteractionResponse +func (b *InteractionResponseBuilder) ClearComponents() *InteractionResponseBuilder { + if b != nil { + b.Data.Components = []Component{} + } + return b +} + +// RemoveComponent removes a Component from the InteractionResponse +func (b *InteractionResponseBuilder) RemoveComponent(i int) *InteractionResponseBuilder { + if b != nil && len(b.Data.Components) > i { + b.Data.Components = append(b.Data.Components[:i], b.Data.Components[i+1:]...) + } + return b +} + +// SetAllowedMentions sets the allowed mentions of the InteractionResponse +func (b *InteractionResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *InteractionResponseBuilder { + b.Data.AllowedMentions = allowedMentions + return b +} + +// SetAllowedMentionsEmpty sets the allowed mentions of the InteractionResponse to nothing +func (b *InteractionResponseBuilder) SetAllowedMentionsEmpty() *InteractionResponseBuilder { + return b.SetAllowedMentions(&AllowedMentions{}) +} + +// SetFlags sets the message flags of the InteractionResponse +func (b *InteractionResponseBuilder) SetFlags(flags MessageFlags) *InteractionResponseBuilder { + b.Data.Flags = flags + return b +} + +// SetEphemeral adds/removes MessageFlagEphemeral to the message flags +func (b *InteractionResponseBuilder) SetEphemeral(ephemeral bool) *InteractionResponseBuilder { + if ephemeral { + b.Data.Flags &= MessageFlagEphemeral + + } else { + b.Data.Flags |= MessageFlagEphemeral + } + return b +} + +// Build returns your built InteractionResponse +func (b *InteractionResponseBuilder) Build() *InteractionResponse { + return &b.InteractionResponse +} + +// BuildData returns your built InteractionResponseData +func (b *InteractionResponseBuilder) BuildData() *InteractionResponseData { + return b.Data } diff --git a/api/message.go b/api/message.go index 35d4c7c2..2ad5b78a 100644 --- a/api/message.go +++ b/api/message.go @@ -179,7 +179,7 @@ type Message struct { Content *string `json:"content,omitempty"` ChannelID Snowflake `json:"channel_id"` Type MessageType `json:"type"` - Flags *MessageFlags `json:"flags"` + Flags MessageFlags `json:"flags"` MessageReference *MessageReference `json:"message_reference,omitempty"` Interaction *MessageInteraction `json:"message_interaction,omitempty"` WebhookID *Snowflake `json:"webhook_id,omitempty"` @@ -190,6 +190,11 @@ type Message struct { LastUpdated *time.Time `json:"last_updated,omitempty"` } +type FullMessage struct { + *Message + UnmarshalComponents []*UnmarshalComponent `json:"components,omitempty"` +} + // MessageReference is a reference to another message type MessageReference struct { MessageID *Snowflake `json:"message_id"` @@ -272,17 +277,6 @@ type MessageUpdate struct { AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` } -// MessageCreate is the struct to create a new Message with -type MessageCreate struct { - Nonce string `json:"nonce,omitempty"` - Content string `json:"content,omitempty"` - Components []Component `json:"components,omitempty"` - TTS bool `json:"tts,omitempty"` - Embed *Embed `json:"embed,omitempty"` - AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - MessageReference *MessageReference `json:"message_reference,omitempty"` -} - // MessageBulkDelete is used to bulk delete Message(s) type MessageBulkDelete struct { Messages []Snowflake `json:"messages"` diff --git a/api/message_builder.go b/api/message_builder.go index 10a986a9..909ee399 100644 --- a/api/message_builder.go +++ b/api/message_builder.go @@ -2,6 +2,17 @@ package api import "fmt" +// MessageCreate is the struct to create a new Message with +type MessageCreate struct { + Nonce string `json:"nonce,omitempty"` + Content string `json:"content,omitempty"` + Components []Component `json:"components,omitempty"` + TTS bool `json:"tts,omitempty"` + Embed *Embed `json:"embed,omitempty"` + AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` + MessageReference *MessageReference `json:"message_reference,omitempty"` +} + // MessageBuilder helper to build Message(s) easier type MessageBuilder struct { MessageCreate @@ -17,6 +28,24 @@ func NewMessageBuilder() *MessageBuilder { } } +// NewMessageBuilderByMessage returns a new MessageBuilder and takes an existing Message +func NewMessageBuilderByMessage(message *Message) *MessageBuilder { + msg := MessageCreate{ + TTS: message.TTS, + Components: message.Components, + AllowedMentions: &DefaultInteractionAllowedMentions, + } + if message.Content != nil { + msg.Content = *message.Content + } + if len(message.Embeds) > 0 { + msg.Embed = message.Embeds[0] + } + return &MessageBuilder{ + MessageCreate: msg, + } +} + // NewMessageBuilderWithEmbed creates a new MessageBuilder with an Embed to be built later func NewMessageBuilderWithEmbed(embed *Embed) *MessageBuilder { return NewMessageBuilder().SetEmbed(embed) @@ -57,6 +86,28 @@ func (b *MessageBuilder) SetComponents(components ...Component) *MessageBuilder return b } +// AddComponents adds the Component(s) to the Message +func (b *MessageBuilder) AddComponents(components ...Component) *MessageBuilder { + b.Components = append(b.Components, components...) + return b +} + +// ClearComponents removes all of the Component(s) of the Message +func (b *MessageBuilder) ClearComponents() *MessageBuilder { + if b != nil { + b.Components = []Component{} + } + return b +} + +// RemoveComponent removes a Component from the Message +func (b *MessageBuilder) RemoveComponent(i int) *MessageBuilder { + if b != nil && len(b.Components) > i { + b.Components = append(b.Components[:i], b.Components[i+1:]...) + } + return b +} + // SetAllowedMentions sets the AllowedMentions of the Message func (b *MessageBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *MessageBuilder { b.AllowedMentions = allowedMentions diff --git a/api/slash_command_response.go b/api/slash_command_response.go deleted file mode 100644 index d41caf8c..00000000 --- a/api/slash_command_response.go +++ /dev/null @@ -1,121 +0,0 @@ -package api - -import "fmt" - -// The SlashCommandResponse is used to specify the message_events options when creating an InteractionResponse -type SlashCommandResponse struct { - TTS bool `json:"tts,omitempty"` - Content string `json:"content,omitempty"` - Embeds []*Embed `json:"embeds,omitempty"` - Components []Component `json:"components,omitempty"` - AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"` - Flags MessageFlags `json:"flags,omitempty"` -} - -// SlashCommandResponseBuilder allows you to create an InteractionResponse with ease -type SlashCommandResponseBuilder struct { - SlashCommandResponse -} - -// NewSlashCommandResponseBuilder returns a new SlashCommandResponseBuilder -func NewSlashCommandResponseBuilder() *SlashCommandResponseBuilder { - return &SlashCommandResponseBuilder{ - SlashCommandResponse: SlashCommandResponse{ - AllowedMentions: &DefaultInteractionAllowedMentions, - }, - } -} - -// SetTTS sets if the InteractionResponse is a tts message -func (b *SlashCommandResponseBuilder) SetTTS(tts bool) *SlashCommandResponseBuilder { - b.TTS = tts - return b -} - -// SetContent sets the content of the InteractionResponse -func (b *SlashCommandResponseBuilder) SetContent(content string) *SlashCommandResponseBuilder { - b.Content = content - return b -} - -// SetContentf sets the content of the InteractionResponse with format -func (b *SlashCommandResponseBuilder) SetContentf(content string, a ...interface{}) *SlashCommandResponseBuilder { - b.Content = fmt.Sprintf(content, a...) - return b -} - -// SetEmbeds sets the embeds of the InteractionResponse -func (b *SlashCommandResponseBuilder) SetEmbeds(embeds ...*Embed) *SlashCommandResponseBuilder { - b.Embeds = embeds - return b -} - -// AddEmbeds adds multiple embeds to the InteractionResponse -func (b *SlashCommandResponseBuilder) AddEmbeds(embeds ...*Embed) *SlashCommandResponseBuilder { - b.Embeds = append(b.Embeds, embeds...) - return b -} - -// ClearEmbeds removes all of the embeds from the InteractionResponse -func (b *SlashCommandResponseBuilder) ClearEmbeds() *SlashCommandResponseBuilder { - if b != nil { - b.Embeds = []*Embed{} - } - return b -} - -// RemoveEmbed removes an embed from the InteractionResponse -func (b *SlashCommandResponseBuilder) RemoveEmbed(i int) *SlashCommandResponseBuilder { - if b != nil && len(b.Embeds) > i { - b.Embeds = append(b.Embeds[:i], b.Embeds[i+1:]...) - } - return b -} - -// SetComponents sets the Component(s) of the InteractionResponse -func (b *SlashCommandResponseBuilder) SetComponents(components ...Component) *SlashCommandResponseBuilder { - b.Components = components - return b -} - -// AddComponents adds the Component(s) to the InteractionResponse -func (b *SlashCommandResponseBuilder) AddComponents(components ...Component) *SlashCommandResponseBuilder { - b.Components = append(b.Components, components...) - return b -} - -// SetAllowedMentions sets the allowed mentions of the InteractionResponse -func (b *SlashCommandResponseBuilder) SetAllowedMentions(allowedMentions *AllowedMentions) *SlashCommandResponseBuilder { - b.AllowedMentions = allowedMentions - return b -} - -// SetAllowedMentionsEmpty sets the allowed mentions of the InteractionResponse to nothing -func (b *SlashCommandResponseBuilder) SetAllowedMentionsEmpty() *SlashCommandResponseBuilder { - return b.SetAllowedMentions(&AllowedMentions{}) -} - -// SetFlags sets the message flags of the InteractionResponse -func (b *SlashCommandResponseBuilder) SetFlags(flags MessageFlags) *SlashCommandResponseBuilder { - b.Flags = flags - return b -} - -// SetEphemeral adds/removes MessageFlagEphemeral to the message flags -func (b *SlashCommandResponseBuilder) SetEphemeral(ephemeral bool) *SlashCommandResponseBuilder { - if ephemeral { - b.Flags &= MessageFlagEphemeral - - } else { - b.Flags |= MessageFlagEphemeral - } - return b -} - -// Build returns your built InteractionResponse -func (b *SlashCommandResponseBuilder) Build() *InteractionResponse { - return &InteractionResponse{ - Type: InteractionResponseTypeChannelMessageWithSource, - Data: &b.SlashCommandResponse, - } -} diff --git a/example/examplebot.go b/example/examplebot.go index 55c6bf27..2b0c7224 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -181,37 +181,26 @@ func rawGatewayEventListener(event *events.RawGatewayEvent) { func buttonClickListener(event *events.ButtonClickEvent) { switch event.CustomID() { case "test": - content := "test2" - err := event.Reply(&api.InteractionResponse{ - Type: api.InteractionResponseTypeButtonResponse, - Data: &api.ButtonResponseData{ - Content: &content, - Components: []api.Component{ - api.NewActionRow( - api.NewPrimaryButton("test2", "test2", api.NewEmoji("✔"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("kittybot", emoteID), false), - ), - }, - }, - }) - if err != nil { + if err := event.ReplyEdit(api.NewInteractionResponseBuilder(). + SetContent("test2"). + SetComponents(api.NewActionRow( + api.NewPrimaryButton("test2", "test2", api.NewEmoji("✔"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("kittybot", emoteID), false), + )). + BuildData(), + ); err != nil { logger.Errorf("error sending interaction response: %s", err) } + case "test2": - content := "test" - err := event.Reply(&api.InteractionResponse{ - Type: api.InteractionResponseTypeButtonResponse, - Data: &api.ButtonResponseData{ - Content: &content, - Components: []api.Component{ - api.NewActionRow( - api.NewPrimaryButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("kittybot", emoteID), false), - ), - }, - }, - }) - if err != nil { + if err := event.ReplyEdit(api.NewInteractionResponseBuilder(). + SetContent("test"). + SetComponents(api.NewActionRow( + api.NewPrimaryButton("test", "test", api.NewEmoji("❌"), false), + api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("kittybot", emoteID), false), + )). + BuildData(), + ); err != nil { logger.Errorf("error sending interaction response: %s", err) } } @@ -228,7 +217,7 @@ func slashCommandListener(event *events.SlashCommandEvent) { AddField("Time", "...", true). AddField("Code", "```go\n"+code+"\n```", false). AddField("Output", "```\n...\n```", false) - _ = event.Reply(api.NewSlashCommandResponseBuilder().SetEmbeds(embed.Build()).Build()) + _ = event.ReplyCreate(api.NewInteractionResponseBuilder().SetEmbeds(embed.Build()).BuildData()) start := time.Now() output, err := gval.Evaluate(code, map[string]interface{}{ @@ -270,23 +259,19 @@ func slashCommandListener(event *events.SlashCommandEvent) { }() case "say": - _ = event.Reply(api.NewSlashCommandResponseBuilder(). + _ = event.Reply(api.NewInteractionResponseBuilder(). SetContent(event.Option("message").String()). SetAllowedMentionsEmpty(). Build(), ) case "test": - if err := event.Reply(api.NewSlashCommandResponseBuilder(). + if err := event.Reply(api.NewInteractionResponseBuilder(). SetContent("test1"). SetEmbeds(api.NewEmbedBuilder().SetDescription("this message should have some buttons").Build()). SetComponents( api.NewActionRow( api.NewPrimaryButton("test", "test", api.NewEmoji("❌"), false), - api.NewLinkButton("KittyBot", "https://kittybot.de", api.NewEmote("kittybot", emoteID), false), - ), - api.NewActionRow( - api.NewPrimaryButton("test2", "test2", api.NewEmoji("✔"), false), ), ). Build(), @@ -299,11 +284,11 @@ func slashCommandListener(event *events.SlashCommandEvent) { role := event.Option("role").Role() err := event.Disgo().RestClient().AddMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { - _ = event.Reply(api.NewSlashCommandResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(green).SetDescriptionf("Added %s to %s", role, user).Build(), ).Build()) } else { - _ = event.Reply(api.NewSlashCommandResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(red).SetDescriptionf("Failed to add %s to %s", role, user).Build(), ).Build()) } @@ -313,11 +298,11 @@ func slashCommandListener(event *events.SlashCommandEvent) { role := event.Option("role").Role() err := event.Disgo().RestClient().RemoveMemberRole(*event.Interaction.GuildID, user.ID, role.ID) if err == nil { - _ = event.Reply(api.NewSlashCommandResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(65280).SetDescriptionf("Removed %s from %s", role, user).Build(), ).Build()) } else { - _ = event.Reply(api.NewSlashCommandResponseBuilder().AddEmbeds( + _ = event.Reply(api.NewInteractionResponseBuilder().AddEmbeds( api.NewEmbedBuilder().SetColor(16711680).SetDescriptionf("Failed to remove %s from %s", role, user).Build(), ).Build()) } diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 959fa3c7..5b117902 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -47,7 +47,7 @@ func (b *EntityBuilderImpl) CreateButtonInteraction(fullInteraction *api.FullInt return &api.ButtonInteraction{ Interaction: b.createInteraction(fullInteraction, updateCache), - Message: b.CreateMessage(fullInteraction.Message, updateCache), + Message: b.CreateMessage(fullInteraction.FullMessage, updateCache), Data: data, } } @@ -108,15 +108,58 @@ func (b *EntityBuilderImpl) CreateUser(user *api.User, updateCache api.CacheStra return user } +func (b *EntityBuilderImpl) createComponent(unmarshalComponent *api.UnmarshalComponent, updateCache api.CacheStrategy) api.Component { + switch unmarshalComponent.ComponentType { + case api.ComponentTypeActionRow: + components := make([]api.Component, len(unmarshalComponent.Components)) + for i, unmarshalC := range unmarshalComponent.Components { + components[i] = b.createComponent(unmarshalC, updateCache) + } + return &api.ActionRow{ + ComponentImpl: api.ComponentImpl{ + ComponentType: api.ComponentTypeActionRow, + }, + Components: components, + } + + case api.ComponentTypeButton: + return &api.Button{ + ComponentImpl: api.ComponentImpl{ + ComponentType: api.ComponentTypeButton, + }, + Style: unmarshalComponent.Style, + Label: unmarshalComponent.Label, + Emote: b.CreateEmote("", unmarshalComponent.Emote, updateCache), + CustomID: unmarshalComponent.CustomID, + URL: unmarshalComponent.URL, + Disabled: unmarshalComponent.Disabled, + } + + default: + b.Disgo().Logger().Errorf("unexpected component type %d received", unmarshalComponent.ComponentType) + return nil + } +} + // CreateMessage returns a new api.Message entity -func (b *EntityBuilderImpl) CreateMessage(message *api.Message, updateCache api.CacheStrategy) *api.Message { +func (b *EntityBuilderImpl) CreateMessage(fullMessage *api.FullMessage, updateCache api.CacheStrategy) *api.Message { + message := fullMessage.Message message.Disgo = b.Disgo() + if message.Member != nil { + message.Member.User = message.Author message.Member = b.CreateMember(*message.GuildID, message.Member, updateCache) } if message.Author != nil { message.Author = b.CreateUser(message.Author, updateCache) } + + if fullMessage.UnmarshalComponents != nil { + for _, component := range fullMessage.UnmarshalComponents { + message.Components = append(message.Components, b.createComponent(component, updateCache)) + } + } + // TODO: should we cache mentioned users, members, etc? if updateCache(b.Disgo()) { return b.Disgo().Cache().CacheMessage(message) diff --git a/internal/handlers/all_handlers.go b/internal/handlers/all_handlers.go index e3f12a41..134b3e95 100644 --- a/internal/handlers/all_handlers.go +++ b/internal/handlers/all_handlers.go @@ -31,6 +31,8 @@ func GetAllHandlers() []api.EventHandler { InteractionCreateWebhookHandler{}, MessageCreateHandler{}, + MessageUpdateHandler{}, + MessageDeleteHandler{}, ReadyHandler{}, diff --git a/internal/handlers/message_create_handler.go b/internal/handlers/message_create_handler.go index 80dba3ad..bd2a7471 100644 --- a/internal/handlers/message_create_handler.go +++ b/internal/handlers/message_create_handler.go @@ -5,7 +5,7 @@ import ( "github.com/DisgoOrg/disgo/api/events" ) -// MessageCreateHandler handles api.MessageCreateGatewayEvent +// MessageCreateHandler handles api.GatewayEventMessageCreate type MessageCreateHandler struct{} // Event returns the raw gateway event Event @@ -15,18 +15,17 @@ func (h MessageCreateHandler) Event() api.GatewayEventType { // New constructs a new payload receiver for the raw gateway event func (h MessageCreateHandler) New() interface{} { - return &api.Message{} + return &api.FullMessage{} } // HandleGatewayEvent handles the specific raw gateway event func (h MessageCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { - message, ok := i.(*api.Message) + fullMessage, ok := i.(*api.FullMessage) if !ok { return } - message.Disgo = disgo - message.Author.Disgo = disgo + message := disgo.EntityBuilder().CreateMessage(fullMessage, api.CacheStrategyYes) genericMessageEvent := events.GenericMessageEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), diff --git a/internal/handlers/message_delete_handler.go b/internal/handlers/message_delete_handler.go index 5ac8282f..3dfad6e7 100644 --- a/internal/handlers/message_delete_handler.go +++ b/internal/handlers/message_delete_handler.go @@ -1 +1,29 @@ package handlers + +import ( + "github.com/DisgoOrg/disgo/api" +) + +type messageDeletePayload struct { + MessageID api.Snowflake `json:"id"` + GuildID *api.Snowflake `json:"guild_id,omitempty"` + ChannelID api.Snowflake `json:"channel_id"` +} + +// MessageDeleteHandler handles api.GatewayEventMessageDelete +type MessageDeleteHandler struct{} + +// Event returns the raw gateway event Event +func (h MessageDeleteHandler) Event() api.GatewayEventType { + return api.GatewayEventMessageDelete +} + +// New constructs a new payload receiver for the raw gateway event +func (h MessageDeleteHandler) New() interface{} { + return &messageDeletePayload{} +} + +// HandleGatewayEvent handles the specific raw gateway event +func (h MessageDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { + //payload, ok := i.(*api.messageDeletePayload) +} diff --git a/internal/handlers/message_update_handler.go b/internal/handlers/message_update_handler.go index 5ac8282f..f3764ce4 100644 --- a/internal/handlers/message_update_handler.go +++ b/internal/handlers/message_update_handler.go @@ -1 +1,21 @@ package handlers + +import "github.com/DisgoOrg/disgo/api" + +// MessageUpdateHandler handles api.GatewayEventMessageUpdate +type MessageUpdateHandler struct{} + +// Event returns the raw gateway event Event +func (h MessageUpdateHandler) Event() api.GatewayEventType { + return api.GatewayEventMessageUpdate +} + +// New constructs a new payload receiver for the raw gateway event +func (h MessageUpdateHandler) New() interface{} { + return &api.FullMessage{} +} + +// HandleGatewayEvent handles the specific raw gateway event +func (h MessageUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { + //fullMessage, ok := i.(*api.FullMessage) +} diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index 74759d8c..e2928e21 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -157,9 +157,10 @@ func (r RestClientImpl) SendMessage(channelID api.Snowflake, message *api.Messag if err != nil { return nil, err } - err = r.Request(compiledRoute, message, &msg) + var fullMsg *api.FullMessage + err = r.Request(compiledRoute, message, &fullMsg) if err == nil { - msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) + msg = r.Disgo().EntityBuilder().CreateMessage(fullMsg, api.CacheStrategyNoWs) } return } @@ -170,9 +171,10 @@ func (r RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowf if err != nil { return nil, err } - err = r.Request(compiledRoute, message, &msg) + var fullMsg *api.FullMessage + err = r.Request(compiledRoute, message, &fullMsg) if err == nil { - msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) + msg = r.Disgo().EntityBuilder().CreateMessage(fullMsg, api.CacheStrategyNoWs) } return } @@ -212,9 +214,10 @@ func (r RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api. if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &msg) + var fullMsg *api.FullMessage + err = r.Request(compiledRoute, nil, &fullMsg) if err == nil { - msg = r.Disgo().EntityBuilder().CreateMessage(msg, api.CacheStrategyNoWs) + msg = r.Disgo().EntityBuilder().CreateMessage(fullMsg, api.CacheStrategyNoWs) } return } From a09d52a70da6747b98b9ffed27a72016cb90e3d7 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 27 May 2021 20:07:44 +0200 Subject: [PATCH 16/22] golint fixes --- api/action_row.go | 2 ++ api/button.go | 9 +++++++++ api/component.go | 6 ++++++ api/emote.go | 5 ++++- api/events/interaction_events.go | 11 +++++++++-- api/interaction.go | 7 +++++-- api/message.go | 1 + 7 files changed, 36 insertions(+), 5 deletions(-) diff --git a/api/action_row.go b/api/action_row.go index 7e9fe4bd..3b1bd0d4 100644 --- a/api/action_row.go +++ b/api/action_row.go @@ -1,5 +1,6 @@ package api +// NewActionRow creates a new ActionRow holding th provided Component(s) func NewActionRow(components ...Component) *ActionRow { return &ActionRow{ ComponentImpl: newComponentImpl(ComponentTypeActionRow), @@ -7,6 +8,7 @@ func NewActionRow(components ...Component) *ActionRow { } } +// ActionRow holds up to 5 Component(s) in a row type ActionRow struct { ComponentImpl Components []Component `json:"components"` diff --git a/api/button.go b/api/button.go index 827df4c2..641ea2c5 100644 --- a/api/button.go +++ b/api/button.go @@ -1,7 +1,9 @@ package api +// ButtonStyle defines how the Button looks like (https://discord.com/assets/7bb017ce52cfd6575e21c058feb3883b.png) type ButtonStyle int +// Supported ButtonStyle(s) const ( ButtonStylePrimary = iota + 1 ButtonStyleSecondary @@ -10,6 +12,7 @@ const ( ButtonStyleLink ) +// NewButton creates a new Button with the provided parameters. Link Button(s) need a url and other Button(s) need a customID func NewButton(style ButtonStyle, label *string, customID string, url string, emote *Emote, disabled bool) *Button { return &Button{ ComponentImpl: newComponentImpl(ComponentTypeButton), @@ -22,26 +25,32 @@ func NewButton(style ButtonStyle, label *string, customID string, url string, em } } +// NewPrimaryButton creates a new Button with ButtonStylePrimary & the provided parameters func NewPrimaryButton(label string, customID string, emote *Emote, disabled bool) *Button { return NewButton(ButtonStylePrimary, &label, customID, "", emote, disabled) } +// NewSecondaryButton creates a new Button with ButtonStyleSecondary & the provided parameters func NewSecondaryButton(label string, customID string, emote *Emote, disabled bool) *Button { return NewButton(ButtonStyleSecondary, &label, customID, "", emote, disabled) } +// NewSuccessButton creates a new Button with ButtonStyleSuccess & the provided parameters func NewSuccessButton(label string, customID string, emote *Emote, disabled bool) *Button { return NewButton(ButtonStyleSuccess, &label, customID, "", emote, disabled) } +// NewDangerButton creates a new Button with ButtonStyleDanger & the provided parameters func NewDangerButton(label string, customID string, emote *Emote, disabled bool) *Button { return NewButton(ButtonStyleDanger, &label, customID, "", emote, disabled) } +// NewLinkButton creates a new link Button with ButtonStyleLink & the provided parameters func NewLinkButton(label string, url string, emote *Emote, disabled bool) *Button { return NewButton(ButtonStyleLink, &label, "", url, emote, disabled) } +// Button can be attacked to all messages & be clicked by a User. If clicked it fires a events.ButtonClickEvent with the declared customID type Button struct { ComponentImpl Style ButtonStyle `json:"style,omitempty"` diff --git a/api/component.go b/api/component.go index 6c734154..bddaa23c 100644 --- a/api/component.go +++ b/api/component.go @@ -1,12 +1,15 @@ package api +// ComponentType defines different Component(s) type ComponentType int +// Supported ComponentType(s) const ( ComponentTypeActionRow = iota + 1 ComponentTypeButton ) +// Component is a general interface each Component needs to implement type Component interface { Type() ComponentType } @@ -15,14 +18,17 @@ func newComponentImpl(componentType ComponentType) ComponentImpl { return ComponentImpl{ComponentType: componentType} } +// ComponentImpl is used to embed in each different ComponentType type ComponentImpl struct { ComponentType ComponentType `json:"type"` } +// Type returns the ComponentType of this Component func (t ComponentImpl) Type() ComponentType { return t.ComponentType } +// UnmarshalComponent is used for easier unmarshalling of different Component(s) type UnmarshalComponent struct { ComponentType ComponentType `json:"type"` Style ButtonStyle `json:"style"` diff --git a/api/emote.go b/api/emote.go index 6b17f5c3..e77ef2d8 100644 --- a/api/emote.go +++ b/api/emote.go @@ -1,18 +1,21 @@ package api +// NewEmote creates a new custom Emote with the given parameters func NewEmote(name string, emoteID Snowflake) *Emote { return &Emote{Name: name, ID: emoteID, Animated: false} } +// NewAnimatedEmote creates a new animated custom Emote with the given parameters func NewAnimatedEmote(name string, emoteID Snowflake) *Emote { return &Emote{Name: name, ID: emoteID, Animated: true} } +// NewEmoji creates a new emoji with the given unicode func NewEmoji(name string) *Emote { return &Emote{Name: name} } -// An Emote allows you to interact with custom emojis in discord. +// Emote allows you to interact with emojis & emotes type Emote struct { Disgo Disgo GuildID Snowflake `json:"guild_id,omitempty"` diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index f8a69f64..4ad347d7 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -55,7 +55,7 @@ func (e *GenericInteractionEvent) DeleteFollowup(messageID api.Snowflake) error return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID) } -// SlashCommandEvent indicates that a slash api.Command was ran in a api.Guild +// SlashCommandEvent indicates that a slash api.Command was ran type SlashCommandEvent struct { GenericInteractionEvent SlashCommandInteraction *api.SlashCommandInteraction @@ -66,7 +66,7 @@ type SlashCommandEvent struct { Options []*api.Option } -// DeferReply replies to the api.SlashCommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource +// DeferReply replies to the api.SlashCommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource and shows a loading state func (e *SlashCommandEvent) DeferReply(ephemeral bool) error { var data *api.InteractionResponseData if ephemeral { @@ -75,6 +75,7 @@ func (e *SlashCommandEvent) DeferReply(ephemeral bool) error { return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredChannelMessageWithSource, Data: data}) } +// ReplyCreate replies to the api.SlashCommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource & api.InteractionResponseData func (e *SlashCommandEvent) ReplyCreate(data *api.InteractionResponseData) error { return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeChannelMessageWithSource, Data: data}) } @@ -122,27 +123,33 @@ func (e SlashCommandEvent) OptionsT(optionType api.CommandOptionType) []*api.Opt return options } +// ButtonClickEvent indicates that a api.Button was clicked type ButtonClickEvent struct { GenericInteractionEvent ButtonInteraction *api.ButtonInteraction } +// DeferEdit replies to the api.ButtonInteraction with api.InteractionResponseTypeDeferredUpdateMessage and cancels the loading state func (e *ButtonClickEvent) DeferEdit() error { return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredUpdateMessage}) } +// ReplyEdit replies to the api.ButtonInteraction with api.InteractionResponseTypeUpdateMessage & api.InteractionResponseData which edits the original api.Message func (e *ButtonClickEvent) ReplyEdit(data *api.InteractionResponseData) error { return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeUpdateMessage, Data: data}) } +// CustomID returns the customID from the called api.Button func (e *ButtonClickEvent) CustomID() string { return e.ButtonInteraction.Data.CustomID } +// ComponentType returns the api.ComponentType from the called api.Button func (e *ButtonClickEvent) ComponentType() string { return e.ButtonInteraction.Data.CustomID } +// Message returns the api.Message the api.Button is called from func (e *ButtonClickEvent) Message() *api.Message { return e.ButtonInteraction.Message } diff --git a/api/interaction.go b/api/interaction.go index 589f15cd..f57498ca 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -5,7 +5,7 @@ import "encoding/json" // InteractionType is the type of Interaction type InteractionType int -// Constants for InteractionType +// Supported InteractionType(s) const ( InteractionTypePing InteractionType = iota + 1 InteractionTypeSlashCommand @@ -77,6 +77,7 @@ func (i *Interaction) DeleteFollowup(messageID Snowflake) error { return i.Disgo.RestClient().DeleteFollowupMessage(i.Disgo.ApplicationID(), i.Token, messageID) } +// FullInteraction is used for easier unmarshalling of different Interaction(s) type FullInteraction struct { ID Snowflake `json:"id"` Type InteractionType `json:"type"` @@ -90,7 +91,7 @@ type FullInteraction struct { Data json.RawMessage `json:"data,omitempty"` } -// An Interaction is the slash command object you receive when a user uses one of your commands +// Interaction holds the general parameters of each Interaction type Interaction struct { Disgo Disgo ID Snowflake `json:"id"` @@ -103,12 +104,14 @@ type Interaction struct { Version int `json:"version"` } +// ButtonInteraction is a specific Interaction when CLicked on Button(s) type ButtonInteraction struct { *Interaction Message *Message `json:"message,omitempty"` Data *ButtonInteractionData `json:"data,omitempty"` } +// SlashCommandInteraction is a specific Interaction when using Command(s) type SlashCommandInteraction struct { *Interaction Data *SlashCommandInteractionData `json:"data,omitempty"` diff --git a/api/message.go b/api/message.go index 2ad5b78a..780eb2ff 100644 --- a/api/message.go +++ b/api/message.go @@ -190,6 +190,7 @@ type Message struct { LastUpdated *time.Time `json:"last_updated,omitempty"` } +// FullMessage is used for easier unmarshalling of Component(s) in Message(s) type FullMessage struct { *Message UnmarshalComponents []*UnmarshalComponent `json:"components,omitempty"` From 1ddfbb2792ce785b960bcf19126790fa069f97cc Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Thu, 27 May 2021 23:42:16 +0200 Subject: [PATCH 17/22] replace slashcommand & applicationcommand with command --- api/entity_builder.go | 2 +- api/events/application_command_events.go | 24 +++++++-------- api/events/interaction_events.go | 22 +++++++------- api/events/listener_adapter.go | 30 +++++++++---------- api/gateway.go | 6 ++-- api/interaction.go | 12 ++++---- api/message.go | 2 +- api/permissions.go | 2 +- api/restclient.go | 2 +- example/examplebot.go | 4 +-- internal/entity_builder_impl.go | 8 ++--- internal/handlers/all_handlers.go | 6 ++-- .../handlers/application_command_create.go | 20 ++++++------- .../handlers/application_command_delete.go | 20 ++++++------- .../handlers/application_command_update.go | 20 ++++++------- .../handlers/interaction_create_handler.go | 8 ++--- internal/restclient_impl.go | 4 +-- 17 files changed, 96 insertions(+), 96 deletions(-) diff --git a/api/entity_builder.go b/api/entity_builder.go index 82776cc4..22c5dc6a 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -16,7 +16,7 @@ type EntityBuilder interface { Disgo() Disgo CreateButtonInteraction(fullInteraction *FullInteraction, updateCache CacheStrategy) *ButtonInteraction - CreateSlashCommandInteraction(fullInteraction *FullInteraction, updateCache CacheStrategy) *SlashCommandInteraction + CreateCommandInteraction(fullInteraction *FullInteraction, updateCache CacheStrategy) *CommandInteraction CreateGlobalCommand(command *Command, updateCache CacheStrategy) *Command diff --git a/api/events/application_command_events.go b/api/events/application_command_events.go index 3b427c71..ba6101f1 100644 --- a/api/events/application_command_events.go +++ b/api/events/application_command_events.go @@ -4,8 +4,8 @@ import ( "github.com/DisgoOrg/disgo/api" ) -// GenericApplicationCommandEvent is called upon receiving either ApplicationCommandCreateEvent, ApplicationCommandUpdateEvent or ApplicationCommandDeleteEvent -type GenericApplicationCommandEvent struct { +// GenericCommandEvent is called upon receiving either CommandCreateEvent, CommandUpdateEvent or CommandDeleteEvent +type GenericCommandEvent struct { GenericEvent CommandID api.Snowflake Command *api.Command @@ -13,25 +13,25 @@ type GenericApplicationCommandEvent struct { } // Guild returns the api.Guild the api.Event got called or nil for global api.Command(s) -func (e GenericApplicationCommandEvent) Guild() *api.Guild { +func (e GenericCommandEvent) Guild() *api.Guild { if e.GuildID == nil { return nil } return e.Disgo().Cache().Guild(*e.GuildID) } -// ApplicationCommandCreateEvent indicates that a new api.Command got created(this can come from any bot!) -type ApplicationCommandCreateEvent struct { - GenericApplicationCommandEvent +// CommandCreateEvent indicates that a new api.Command got created(this can come from any bot!) +type CommandCreateEvent struct { + GenericCommandEvent } -// ApplicationCommandUpdateEvent indicates that a api.Command got updated(this can come from any bot!) -type ApplicationCommandUpdateEvent struct { - GenericApplicationCommandEvent +// CommandUpdateEvent indicates that a api.Command got updated(this can come from any bot!) +type CommandUpdateEvent struct { + GenericCommandEvent OldCommand *api.Command } -// ApplicationCommandDeleteEvent indicates that a api.Command got deleted(this can come from any bot!) -type ApplicationCommandDeleteEvent struct { - GenericApplicationCommandEvent +// CommandDeleteEvent indicates that a api.Command got deleted(this can come from any bot!) +type CommandDeleteEvent struct { + GenericCommandEvent } diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index 4ad347d7..1d175b23 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -55,10 +55,10 @@ func (e *GenericInteractionEvent) DeleteFollowup(messageID api.Snowflake) error return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID) } -// SlashCommandEvent indicates that a slash api.Command was ran -type SlashCommandEvent struct { +// CommandEvent indicates that a slash api.Command was ran +type CommandEvent struct { GenericInteractionEvent - SlashCommandInteraction *api.SlashCommandInteraction + CommandInteraction *api.CommandInteraction CommandID api.Snowflake CommandName string SubCommandName *string @@ -66,8 +66,8 @@ type SlashCommandEvent struct { Options []*api.Option } -// DeferReply replies to the api.SlashCommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource and shows a loading state -func (e *SlashCommandEvent) DeferReply(ephemeral bool) error { +// DeferReply replies to the api.CommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource and shows a loading state +func (e *CommandEvent) DeferReply(ephemeral bool) error { var data *api.InteractionResponseData if ephemeral { data = &api.InteractionResponseData{Flags: api.MessageFlagEphemeral} @@ -75,13 +75,13 @@ func (e *SlashCommandEvent) DeferReply(ephemeral bool) error { return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredChannelMessageWithSource, Data: data}) } -// ReplyCreate replies to the api.SlashCommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource & api.InteractionResponseData -func (e *SlashCommandEvent) ReplyCreate(data *api.InteractionResponseData) error { +// ReplyCreate replies to the api.CommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource & api.InteractionResponseData +func (e *CommandEvent) ReplyCreate(data *api.InteractionResponseData) error { return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeChannelMessageWithSource, Data: data}) } // CommandPath returns the api.Command path -func (e SlashCommandEvent) CommandPath() string { +func (e CommandEvent) CommandPath() string { path := e.CommandName if e.SubCommandName != nil { path += "/" + *e.SubCommandName @@ -93,7 +93,7 @@ func (e SlashCommandEvent) CommandPath() string { } // Option returns an Option by name -func (e SlashCommandEvent) Option(name string) *api.Option { +func (e CommandEvent) Option(name string) *api.Option { options := e.OptionN(name) if len(options) == 0 { return nil @@ -102,7 +102,7 @@ func (e SlashCommandEvent) Option(name string) *api.Option { } // OptionN returns Option(s) by name -func (e SlashCommandEvent) OptionN(name string) []*api.Option { +func (e CommandEvent) OptionN(name string) []*api.Option { options := make([]*api.Option, 0) for _, option := range e.Options { if option.Name == name { @@ -113,7 +113,7 @@ func (e SlashCommandEvent) OptionN(name string) []*api.Option { } // OptionsT returns Option(s) by api.CommandOptionType -func (e SlashCommandEvent) OptionsT(optionType api.CommandOptionType) []*api.Option { +func (e CommandEvent) OptionsT(optionType api.CommandOptionType) []*api.Option { options := make([]*api.Option, 0) for _, option := range e.Options { if option.Type == optionType { diff --git a/api/events/listener_adapter.go b/api/events/listener_adapter.go index 615b4c79..75ded836 100644 --- a/api/events/listener_adapter.go +++ b/api/events/listener_adapter.go @@ -16,10 +16,10 @@ type ListenerAdapter struct { OnReadyEvent func(event *ReadyEvent) // api.Command Events - OnGenericApplicationCommandEvent func(event *GenericApplicationCommandEvent) - OnApplicationCommandCreate func(event *ApplicationCommandCreateEvent) - OnApplicationCommandUpdate func(event *ApplicationCommandUpdateEvent) - OnApplicationCommandDelete func(event *ApplicationCommandDeleteEvent) + OnGenericCommandEvent func(event *GenericCommandEvent) + OnCommandCreate func(event *CommandCreateEvent) + OnCommandUpdate func(event *CommandUpdateEvent) + OnCommandDelete func(event *CommandDeleteEvent) // api.Channel Events OnGenericChannelEvent func(event *GenericChannelEvent) @@ -123,7 +123,7 @@ type ListenerAdapter struct { // api.Interaction Events OnGenericInteractionEvent func(event *GenericInteractionEvent) - OnSlashCommand func(event *SlashCommandEvent) + OnCommand func(event *CommandEvent) OnButtonClick func(event *ButtonClickEvent) // api.Message Events @@ -181,20 +181,20 @@ func (l ListenerAdapter) OnEvent(event interface{}) { } // api.Command Events - case GenericApplicationCommandEvent: - if listener := l.OnGenericApplicationCommandEvent; listener != nil { + case GenericCommandEvent: + if listener := l.OnGenericCommandEvent; listener != nil { listener(&e) } - case ApplicationCommandCreateEvent: - if listener := l.OnApplicationCommandCreate; listener != nil { + case CommandCreateEvent: + if listener := l.OnCommandCreate; listener != nil { listener(&e) } - case ApplicationCommandUpdateEvent: - if listener := l.OnApplicationCommandUpdate; listener != nil { + case CommandUpdateEvent: + if listener := l.OnCommandUpdate; listener != nil { listener(&e) } - case ApplicationCommandDeleteEvent: - if listener := l.OnApplicationCommandDelete; listener != nil { + case CommandDeleteEvent: + if listener := l.OnCommandDelete; listener != nil { listener(&e) } @@ -507,8 +507,8 @@ func (l ListenerAdapter) OnEvent(event interface{}) { if listener := l.OnGenericInteractionEvent; listener != nil { listener(&e) } - case SlashCommandEvent: - if listener := l.OnSlashCommand; listener != nil { + case CommandEvent: + if listener := l.OnCommand; listener != nil { listener(&e) } case ButtonClickEvent: diff --git a/api/gateway.go b/api/gateway.go index cc11abd9..e0835ee7 100644 --- a/api/gateway.go +++ b/api/gateway.go @@ -62,9 +62,9 @@ const ( GatewayEventResumed GatewayEventType = "RESUMED" GatewayEventReconnect GatewayEventType = "RECONNECT" GatewayEventInvalidSession GatewayEventType = "INVALID_SESSION" - GatewayEventApplicationCommandCreate GatewayEventType = "APPLICATION_COMMAND_CREATE" - GatewayEventApplicationCommandUpdate GatewayEventType = "APPLICATION_COMMAND_UPDATE" - GatewayEventApplicationCommandDelete GatewayEventType = "APPLICATION_COMMAND_DELETE" + GatewayEventCommandCreate GatewayEventType = "APPLICATION_COMMAND_CREATE" + GatewayEventCommandUpdate GatewayEventType = "APPLICATION_COMMAND_UPDATE" + GatewayEventCommandDelete GatewayEventType = "APPLICATION_COMMAND_DELETE" GatewayEventChannelCreate GatewayEventType = "CHANNEL_CREATE" GatewayEventChannelUpdate GatewayEventType = "CHANNEL_UPDATE" GatewayEventChannelDelete GatewayEventType = "CHANNEL_DELETE" diff --git a/api/interaction.go b/api/interaction.go index f57498ca..fad71554 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -8,7 +8,7 @@ type InteractionType int // Supported InteractionType(s) const ( InteractionTypePing InteractionType = iota + 1 - InteractionTypeSlashCommand + InteractionTypeCommand InteractionTypeComponent ) @@ -111,10 +111,10 @@ type ButtonInteraction struct { Data *ButtonInteractionData `json:"data,omitempty"` } -// SlashCommandInteraction is a specific Interaction when using Command(s) -type SlashCommandInteraction struct { +// CommandInteraction is a specific Interaction when using Command(s) +type CommandInteraction struct { *Interaction - Data *SlashCommandInteractionData `json:"data,omitempty"` + Data *CommandInteractionData `json:"data,omitempty"` } // ButtonInteractionData is the command data payload @@ -123,8 +123,8 @@ type ButtonInteractionData struct { ComponentType ComponentType `json:"component_type"` } -// SlashCommandInteractionData is the command data payload -type SlashCommandInteractionData struct { +// CommandInteractionData is the command data payload +type CommandInteractionData struct { ID Snowflake `json:"id"` Name string `json:"name"` Resolved *Resolved `json:"resolved,omitempty"` diff --git a/api/message.go b/api/message.go index 780eb2ff..1e2a8cd5 100644 --- a/api/message.go +++ b/api/message.go @@ -30,7 +30,7 @@ const ( MessageTypeGuildDiscoveryFinalWarning _ MessageTypeReply - MessageTypeApplicationCommand + MessageTypeCommand ) // The MessageFlags of a Message diff --git a/api/permissions.go b/api/permissions.go index 48b64be6..86346afb 100644 --- a/api/permissions.go +++ b/api/permissions.go @@ -133,7 +133,7 @@ const ( PermissionManageRoles PermissionManageWebhooks PermissionManageEmojis - PermissionUseSlashCommands + PermissionUseCommands ) // Constants for the different bit offsets of general permissions diff --git a/api/restclient.go b/api/restclient.go index 3eaba0d0..a619cc77 100644 --- a/api/restclient.go +++ b/api/restclient.go @@ -12,7 +12,7 @@ var ( ErrUnauthorized = errors.New("not authorized for this endpoint") ErrBadRequest = errors.New("bad request please check your request") ErrRatelimited = errors.New("too many requests") - ErrTooMuchApplicationCommands = errors.New("you can provide a max of 100 application commands") + ErrTooMuchCommands = errors.New("you can provide a max of 100 application commands") ) // ErrorResponse contains custom errors from discord diff --git a/example/examplebot.go b/example/examplebot.go index 2b0c7224..3cf4dacc 100644 --- a/example/examplebot.go +++ b/example/examplebot.go @@ -43,7 +43,7 @@ func main() { OnRawGateway: rawGatewayEventListener, OnGuildAvailable: guildAvailListener, OnGuildMessageCreate: messageListener, - OnSlashCommand: slashCommandListener, + OnCommand: commandListener, OnButtonClick: buttonClickListener, }). Build() @@ -206,7 +206,7 @@ func buttonClickListener(event *events.ButtonClickEvent) { } } -func slashCommandListener(event *events.SlashCommandEvent) { +func commandListener(event *events.CommandEvent) { switch event.CommandName { case "eval": go func() { diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index 5b117902..fafb3bb7 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -52,9 +52,9 @@ func (b *EntityBuilderImpl) CreateButtonInteraction(fullInteraction *api.FullInt } } -// CreateSlashCommandInteraction creates a api.SlashCommandInteraction from the full interaction response -func (b *EntityBuilderImpl) CreateSlashCommandInteraction(fullInteraction *api.FullInteraction, updateCache api.CacheStrategy) *api.SlashCommandInteraction { - var data *api.SlashCommandInteractionData +// CreateCommandInteraction creates a api.CommandInteraction from the full interaction response +func (b *EntityBuilderImpl) CreateCommandInteraction(fullInteraction *api.FullInteraction, updateCache api.CacheStrategy) *api.CommandInteraction { + var data *api.CommandInteractionData _ = json.Unmarshal(fullInteraction.Data, &data) if data.Resolved != nil { @@ -84,7 +84,7 @@ func (b *EntityBuilderImpl) CreateSlashCommandInteraction(fullInteraction *api.F }*/ } - return &api.SlashCommandInteraction{ + return &api.CommandInteraction{ Interaction: b.createInteraction(fullInteraction, updateCache), Data: data, } diff --git a/internal/handlers/all_handlers.go b/internal/handlers/all_handlers.go index 134b3e95..1bbc90b8 100644 --- a/internal/handlers/all_handlers.go +++ b/internal/handlers/all_handlers.go @@ -7,9 +7,9 @@ import ( // GetAllHandlers returns all api.GatewayEventHandler(s) func GetAllHandlers() []api.EventHandler { return []api.EventHandler{ - ApplicationCommandCreateHandler{}, - ApplicationCommandDeleteHandler{}, - ApplicationCommandUpdateHandler{}, + CommandCreateHandler{}, + CommandDeleteHandler{}, + CommandUpdateHandler{}, ChannelCreateHandler{}, ChannelDeleteHandler{}, diff --git a/internal/handlers/application_command_create.go b/internal/handlers/application_command_create.go index 71d6de9e..fd21d2db 100644 --- a/internal/handlers/application_command_create.go +++ b/internal/handlers/application_command_create.go @@ -5,21 +5,21 @@ import ( "github.com/DisgoOrg/disgo/api/events" ) -// ApplicationCommandCreateHandler handles api.ApplicationCommandCreateEvent -type ApplicationCommandCreateHandler struct{} +// CommandCreateHandler handles api.CommandCreateEvent +type CommandCreateHandler struct{} // Event returns the raw gateway event Event -func (h ApplicationCommandCreateHandler) Event() api.GatewayEventType { - return api.GatewayEventApplicationCommandCreate +func (h CommandCreateHandler) Event() api.GatewayEventType { + return api.GatewayEventCommandCreate } // New constructs a new payload receiver for the raw gateway event -func (h ApplicationCommandCreateHandler) New() interface{} { +func (h CommandCreateHandler) New() interface{} { return &api.Command{} } // HandleGatewayEvent handles the specific raw gateway event -func (h ApplicationCommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { +func (h CommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { command, ok := i.(*api.Command) if !ok { return @@ -37,15 +37,15 @@ func (h ApplicationCommandCreateHandler) HandleGatewayEvent(disgo api.Disgo, eve command = disgo.EntityBuilder().CreateGlobalCommand(command, cacheStrategy) } - genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ + genericCommandEvent := events.GenericCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, Command: command, GuildID: command.GuildID, } - eventManager.Dispatch(genericApplicationCommandEvent) + eventManager.Dispatch(genericCommandEvent) - eventManager.Dispatch(events.ApplicationCommandCreateEvent{ - GenericApplicationCommandEvent: genericApplicationCommandEvent, + eventManager.Dispatch(events.CommandCreateEvent{ + GenericCommandEvent: genericCommandEvent, }) } diff --git a/internal/handlers/application_command_delete.go b/internal/handlers/application_command_delete.go index d4353758..68cb449b 100644 --- a/internal/handlers/application_command_delete.go +++ b/internal/handlers/application_command_delete.go @@ -5,21 +5,21 @@ import ( "github.com/DisgoOrg/disgo/api/events" ) -// ApplicationCommandDeleteHandler handles api.ApplicationCommandCreateEvent -type ApplicationCommandDeleteHandler struct{} +// CommandDeleteHandler handles api.CommandCreateEvent +type CommandDeleteHandler struct{} // Event returns the raw gateway event Event -func (h ApplicationCommandDeleteHandler) Event() api.GatewayEventType { - return api.GatewayEventApplicationCommandDelete +func (h CommandDeleteHandler) Event() api.GatewayEventType { + return api.GatewayEventCommandDelete } // New constructs a new payload receiver for the raw gateway event -func (h ApplicationCommandDeleteHandler) New() interface{} { +func (h CommandDeleteHandler) New() interface{} { return &api.Command{} } // HandleGatewayEvent handles the specific raw gateway event -func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { +func (h CommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { command, ok := i.(*api.Command) if !ok { return @@ -36,15 +36,15 @@ func (h ApplicationCommandDeleteHandler) HandleGatewayEvent(disgo api.Disgo, eve command = disgo.EntityBuilder().CreateGlobalCommand(command, api.CacheStrategyNo) } - genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ + genericCommandEvent := events.GenericCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, Command: command, GuildID: command.GuildID, } - eventManager.Dispatch(genericApplicationCommandEvent) + eventManager.Dispatch(genericCommandEvent) - eventManager.Dispatch(events.ApplicationCommandDeleteEvent{ - GenericApplicationCommandEvent: genericApplicationCommandEvent, + eventManager.Dispatch(events.CommandDeleteEvent{ + GenericCommandEvent: genericCommandEvent, }) } diff --git a/internal/handlers/application_command_update.go b/internal/handlers/application_command_update.go index 341d7edc..8bca2b93 100644 --- a/internal/handlers/application_command_update.go +++ b/internal/handlers/application_command_update.go @@ -5,21 +5,21 @@ import ( "github.com/DisgoOrg/disgo/api/events" ) -// ApplicationCommandUpdateHandler handles api.ApplicationCommandCreateEvent -type ApplicationCommandUpdateHandler struct{} +// CommandUpdateHandler handles api.CommandCreateEvent +type CommandUpdateHandler struct{} // Event returns the raw gateway event Event -func (h ApplicationCommandUpdateHandler) Event() api.GatewayEventType { - return api.GatewayEventApplicationCommandUpdate +func (h CommandUpdateHandler) Event() api.GatewayEventType { + return api.GatewayEventCommandUpdate } // New constructs a new payload receiver for the raw gateway event -func (h ApplicationCommandUpdateHandler) New() interface{} { +func (h CommandUpdateHandler) New() interface{} { return &api.Command{} } // HandleGatewayEvent handles the specific raw gateway event -func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { +func (h CommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, i interface{}) { command, ok := i.(*api.Command) if !ok { return @@ -39,16 +39,16 @@ func (h ApplicationCommandUpdateHandler) HandleGatewayEvent(disgo api.Disgo, eve command = disgo.EntityBuilder().CreateGlobalCommand(command, api.CacheStrategyYes) } - genericApplicationCommandEvent := events.GenericApplicationCommandEvent{ + genericCommandEvent := events.GenericCommandEvent{ GenericEvent: events.NewEvent(disgo, sequenceNumber), CommandID: command.ID, Command: command, GuildID: command.GuildID, } - eventManager.Dispatch(genericApplicationCommandEvent) + eventManager.Dispatch(genericCommandEvent) - eventManager.Dispatch(events.ApplicationCommandUpdateEvent{ - GenericApplicationCommandEvent: genericApplicationCommandEvent, + eventManager.Dispatch(events.CommandUpdateEvent{ + GenericCommandEvent: genericCommandEvent, // always nil for not our own commands OldCommand: oldCommand, }) diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index 0d3cea37..4bb2fff4 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -36,8 +36,8 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN } switch fullInteraction.Type { - case api.InteractionTypeSlashCommand: - interaction := disgo.EntityBuilder().CreateSlashCommandInteraction(fullInteraction, api.CacheStrategyYes) + case api.InteractionTypeCommand: + interaction := disgo.EntityBuilder().CreateCommandInteraction(fullInteraction, api.CacheStrategyYes) genericInteractionEvent.Interaction = interaction.Interaction eventManager.Dispatch(genericInteractionEvent) @@ -68,9 +68,9 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN }) } - eventManager.Dispatch(events.SlashCommandEvent{ + eventManager.Dispatch(events.CommandEvent{ GenericInteractionEvent: genericInteractionEvent, - SlashCommandInteraction: interaction, + CommandInteraction: interaction, CommandID: interaction.Data.ID, CommandName: interaction.Data.Name, SubCommandName: subCommandName, diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index e2928e21..17aa0fdf 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -534,7 +534,7 @@ func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands return nil, err } if len(commands) > 100 { - err = api.ErrTooMuchApplicationCommands + err = api.ErrTooMuchCommands return } err = r.Request(compiledRoute, commands, &cmds) @@ -607,7 +607,7 @@ func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID ap return nil, err } if len(commands) > 100 { - err = api.ErrTooMuchApplicationCommands + err = api.ErrTooMuchCommands return } err = r.Request(compiledRoute, commands, &cmds) From bdd32f3b5300046e46a451a5ec055c94b9cb3454 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 28 May 2021 03:08:33 +0200 Subject: [PATCH 18/22] update to external rest client --- api/endpoints/api_route.go | 47 ---- api/endpoints/cdn_route.go | 66 ------ api/endpoints/custom_route.go | 30 --- api/endpoints/endpoints.go | 209 ----------------- api/endpoints/methods.go | 17 -- api/endpoints/route.go | 56 ----- api/endpoints/route_test.go | 31 --- api/guild.go | 10 +- api/invite.go | 4 +- api/restclient.go | 6 +- api/user.go | 12 +- example/go.sum | 6 + go.mod | 1 + go.sum | 2 + internal/gateway_impl.go | 8 +- internal/restclient_impl.go | 430 +++++++++++++--------------------- 16 files changed, 195 insertions(+), 740 deletions(-) delete mode 100644 api/endpoints/api_route.go delete mode 100644 api/endpoints/cdn_route.go delete mode 100644 api/endpoints/custom_route.go delete mode 100644 api/endpoints/endpoints.go delete mode 100644 api/endpoints/methods.go delete mode 100644 api/endpoints/route.go delete mode 100644 api/endpoints/route_test.go diff --git a/api/endpoints/api_route.go b/api/endpoints/api_route.go deleted file mode 100644 index 887d0d13..00000000 --- a/api/endpoints/api_route.go +++ /dev/null @@ -1,47 +0,0 @@ -package endpoints - -// APIRoute is a basic struct containing Method and URL -type APIRoute struct { - Route - method Method -} - -// Compile returns a CompiledAPIRoute -func (r APIRoute) Compile(args ...interface{}) (*CompiledAPIRoute, error) { - compiledRoute, err := r.Route.Compile(args...) - if err != nil { - return nil, err - } - return &CompiledAPIRoute{ - CompiledRoute: compiledRoute, - method: r.method, - }, nil -} - -// Method returns the request method used by the route -func (r APIRoute) Method() Method { - return r.method -} - -// NewAPIRoute generates a new discord api route struct -func NewAPIRoute(method Method, url string) APIRoute { - return APIRoute{ - Route: Route{ - baseRoute: API, - route: url, - paramCount: countParams(url), - }, - method: method, - } -} - -// CompiledAPIRoute is APIRoute compiled with all URL args -type CompiledAPIRoute struct { - *CompiledRoute - method Method -} - -// Method returns the request method used by the route -func (r CompiledAPIRoute) Method() Method { - return r.method -} diff --git a/api/endpoints/cdn_route.go b/api/endpoints/cdn_route.go deleted file mode 100644 index 7df913d3..00000000 --- a/api/endpoints/cdn_route.go +++ /dev/null @@ -1,66 +0,0 @@ -package endpoints - -import ( - "errors" -) - -// FileExtension is the type of an image on Discord's CDN -type FileExtension string - -// The available FileExtension(s) -const ( - PNG FileExtension = "png" - JPEG FileExtension = "jpg" - WEBP FileExtension = "webp" - GIF FileExtension = "gif" - BLANK FileExtension = "" -) - -func (f FileExtension) String() string { - return string(f) -} - -// CDNRoute is a route for interacting with images hosted on discord's CDN -type CDNRoute struct { - Route - supportedFileExtensions []FileExtension -} - -// NewCDNRoute generates a new discord cdn route struct -func NewCDNRoute(url string, supportedFileExtensions ...FileExtension) CDNRoute { - return CDNRoute{ - Route: Route{ - baseRoute: CDN, - route: url, - paramCount: countParams(url), - }, - supportedFileExtensions: supportedFileExtensions, - } -} - -// Compile builds a full request URL based on provided arguments -func (r CDNRoute) Compile(fileExtension FileExtension, args ...interface{}) (*CompiledCDNRoute, error) { - supported := false - for _, supportedFileExtension := range r.supportedFileExtensions { - if supportedFileExtension == fileExtension { - supported = true - } - } - if !supported { - return nil, errors.New("provided file extension: " + fileExtension.String() + " is not supported by discord on this endpoint!") - } - compiledRoute, err := r.Route.Compile(args...) - if err != nil { - return nil, err - } - compiledRoute.route += fileExtension.String() - compiledCDNRoute := &CompiledCDNRoute{ - CompiledRoute: compiledRoute, - } - return compiledCDNRoute, nil -} - -// CompiledCDNRoute is CDNRoute compiled with all URL args -type CompiledCDNRoute struct { - *CompiledRoute -} diff --git a/api/endpoints/custom_route.go b/api/endpoints/custom_route.go deleted file mode 100644 index 64b26672..00000000 --- a/api/endpoints/custom_route.go +++ /dev/null @@ -1,30 +0,0 @@ -package endpoints - -// CustomRoute is APIRoute but custom for you -type CustomRoute struct { - APIRoute -} - -// Compile returns a CompiledAPIRoute -func (r CustomRoute) Compile(args ...interface{}) (*CompiledAPIRoute, error) { - compiledRoute, err := r.Route.Compile(args...) - if err != nil { - return nil, err - } - return &CompiledAPIRoute{ - CompiledRoute: compiledRoute, - method: r.method, - }, nil -} - -// NewCustomRoute generates a new custom route struct -func NewCustomRoute(method Method, url string) APIRoute { - return APIRoute{ - Route: Route{ - baseRoute: "", - route: url, - paramCount: countParams(url), - }, - method: method, - } -} diff --git a/api/endpoints/endpoints.go b/api/endpoints/endpoints.go deleted file mode 100644 index d335c1f5..00000000 --- a/api/endpoints/endpoints.go +++ /dev/null @@ -1,209 +0,0 @@ -package endpoints - -// Discord Endpoint Constants -const ( - APIVersion = "8" - Base = "https://discord.com/" - CDN = "https://cdn.discordapp.com" - API = Base + "api/v" + APIVersion -) - -// Misc -var ( - GetGateway = NewAPIRoute(GET, "/gateway") - GetGatewayBot = NewAPIRoute(GET, "/gateway/bot") - GetBotApplication = NewAPIRoute(GET, "/oauth2/applications/@me") -) - -// Interactions -var ( - GetGlobalCommands = NewAPIRoute(GET, "/applications/{application.id}/commands") - GetGlobalCommand = NewAPIRoute(GET, "/applications/{application.id}/command/{command.id}") - CreateGlobalCommand = NewAPIRoute(POST, "/applications/{application.id}/commands") - SetGlobalCommands = NewAPIRoute(PUT, "/applications/{application.id}/commands") - EditGlobalCommand = NewAPIRoute(PATCH, "/applications/{application.id}/commands/{command.id}") - DeleteGlobalCommand = NewAPIRoute(DELETE, "/applications/{application.id}/commands") - - GetGuildCommands = NewAPIRoute(GET, "/applications/{application.id}/guilds/{guild.id}/commands") - GetGuildCommand = NewAPIRoute(GET, "/applications/{application.id}/guilds/{guild.id}/command/{command.id}") - CreateGuildCommand = NewAPIRoute(POST, "/applications/{application.id}/guilds/{guild.id}/commands") - SetGuildCommands = NewAPIRoute(PUT, "/applications/{application.id}/guilds/{guild.id}/commands") - EditGuildCommand = NewAPIRoute(PATCH, "/applications/{application.id}/guilds/{guild.id}/commands/{command.id}") - DeleteGuildCommand = NewAPIRoute(DELETE, "/applications/{application.id}/guilds/{guild.id}/commands") - - GetGuildCommandPermissions = NewAPIRoute(GET, "/applications/{application.id}/guilds/{guild.id}/commands/permissions") - GetGuildCommandPermission = NewAPIRoute(GET, "/applications/{application.id}/guilds/{guild.id}/commands/{command.id}/permissions") - SetGuildCommandsPermissions = NewAPIRoute(PUT, "/applications/{application.id}/guilds/{guild.id}/commands/permissions") - SetGuildCommandPermissions = NewAPIRoute(PUT, "/applications/{application.id}/guilds/{guild.id}/commands/{command.id}/permissions") - - CreateInteractionResponse = NewAPIRoute(POST, "/interactions/{interaction.id}/{interaction.token}/callback") - EditInteractionResponse = NewAPIRoute(PATCH, "/webhooks/{application.id}/{interaction.token}/messages/@original") - DeleteInteractionResponse = NewAPIRoute(DELETE, "/webhooks/{application.id}/{interaction.token}/messages/@original") - - CreateFollowupMessage = NewAPIRoute(POST, "/webhooks/{application.id}/{interaction.token}") - EditFollowupMessage = NewAPIRoute(PATCH, "/webhooks/{application.id}/{interaction.token}/messages/{message.id}") - DeleteFollowupMessage = NewAPIRoute(DELETE, "/webhooks/{application.id}/{interaction.token}/messages/{message.id}") -) - -// Users -var ( - GetUser = NewAPIRoute(GET, "/users/{user.id}") - GetSelfUser = NewAPIRoute(GET, "/users/@me") - UpdateSelfUser = NewAPIRoute(PATCH, "/users/@me") - GetGuilds = NewAPIRoute(GET, "/users/@me/guilds") - LeaveGuild = NewAPIRoute(DELETE, "/users/@me/guilds/{guild.id}") - GetDMChannels = NewAPIRoute(GET, "/users/@me/channels") - CreateDMChannel = NewAPIRoute(POST, "/users/@me/channels") -) - -// Guilds -var ( - GetGuild = NewAPIRoute(GET, "/guilds/{guild.id}") - CreateGuild = NewAPIRoute(POST, "/guilds") - UpdateGuild = NewAPIRoute(PATCH, "/guilds/{guild.id}") - DeleteGuild = NewAPIRoute(DELETE, "/guilds/{guild.id}") - GetVanityURL = NewAPIRoute(GET, "/guilds/{guild.id}/vanity-url") - - CreateChannel = NewAPIRoute(POST, "/guilds/{guild.id}/channels") - GetChannels = NewAPIRoute(GET, "/guilds/{guild.id}/channels") - UpdateChannels = NewAPIRoute(PATCH, "/guilds/{guild.id}/channels") - - GetBans = NewAPIRoute(GET, "/guilds/{guild.id}/bans") - GetBan = NewAPIRoute(GET, "/guilds/{guild.id}/bans/{user.id}") - CreateBan = NewAPIRoute(POST, "/guilds/{guild.id}/bans/{user.id}") - DeleteBan = NewAPIRoute(DELETE, "/guilds/{guild.id}/bans/{user.id}") - - GetMember = NewAPIRoute(GET, "/guilds/{guild.id}/members/{user.id}") - GetMembers = NewAPIRoute(GET, "/guilds/{guild.id}/members") - AddMember = NewAPIRoute(PUT, "/guilds/{guild.id}/members/{user.id}") - UpdateMember = NewAPIRoute(PATCH, "/guilds/{guild.id}/members/{user.id}") - RemoveMember = NewAPIRoute(DELETE, "/guilds/{guild.id}/members/{user.id}") - RemoveMemberReason = NewAPIRoute(DELETE, "/guilds/{guild.id}/members/{user.id}?reason={reason}") - AddMemberRole = NewAPIRoute(PUT, "/guilds/{guild.id}/members/{user.id}/roles/{role.id}") - RemoveMemberRole = NewAPIRoute(DELETE, "/guilds/{guild.id}/members/{user.id}/roles/{role.id}") - - UpdateSelfNick = NewAPIRoute(PATCH, "/guilds/{guild.id}/members/@me/nick") - - PrunableCount = NewAPIRoute(GET, "/guilds/{guild.id}/prune") - PruneMembers = NewAPIRoute(POST, "/guilds/{guild.id}/prune") - - GetGuildWebhooks = NewAPIRoute(GET, "/guilds/{guild.id}/webhooks") - - GetAuditLogs = NewAPIRoute(GET, "/guilds/{guild.id}/audit-logs") - - GetVoiceRegions = NewAPIRoute(GET, "/guilds/{guild.id}/regions") - - GetIntegrations = NewAPIRoute(GET, "/guilds/{guild.id}/integrations") - CreateIntegration = NewAPIRoute(POST, "/guilds/{guild.id}/integrations") - UpdateIntegration = NewAPIRoute(PATCH, "/guilds/{guild.id}/integrations/{integration.id}") - DeleteIntegration = NewAPIRoute(DELETE, "/guilds/{guild.id}/integrations/{integration.id}") - SyncIntegration = NewAPIRoute(POST, "/guilds/{guild.id}/integrations/{integration.id}/sync") -) - -// Roles -var ( - GetRoles = NewAPIRoute(GET, "/guilds/{guild.id}/roles") - GetRole = NewAPIRoute(GET, "/guilds/{guild.id}/roles/{role.id}") - CreateRole = NewAPIRoute(POST, "/guilds/{guild.id}/roles") - UpdateRoles = NewAPIRoute(PATCH, "/guilds/{guild.id}/roles") - UpdateRole = NewAPIRoute(PATCH, "/guilds/{guild.id}/roles/{role.id}") - UpdateRolePositions = NewAPIRoute(PATCH, "/guilds/{guild.id}/roles") - DelteRole = NewAPIRoute(DELETE, "/guilds/{guild.id}/roles/{role.id}") -) - -// Channels -var ( - GetChannel = NewAPIRoute(GET, "/channels/{channel.id}") - UpdateChannel = NewAPIRoute(PATCH, "/channels/{channel.id}") - DeleteChannel = NewAPIRoute(DELETE, "/channels/{channel.id}") - - GetWebhooks = NewAPIRoute(GET, "/channels/{channel.id}/webhooks") - CreateWebhook = NewAPIRoute(POST, "/channels/{channel.id}/webhooks") - - GetPermissionOverrides = NewAPIRoute(GET, "/channels/{channel.id}/permissions") - GetPermissionOverride = NewAPIRoute(GET, "/channels/{channel.id}/permissions/{overwrite.id}") - CreatePermissionOverride = NewAPIRoute(PUT, "/channels/{channel.id}/permissions/{overwrite.id}") - UpdatePermissionOverride = NewAPIRoute(PUT, "/channels/{channel.id}/permissions/{overwrite.id}") - DeletePermissionOverride = NewAPIRoute(DELETE, "/channels/{channel.id}/permissions/{overwrite.id}") - - SendTyping = NewAPIRoute(POST, "/channels/{channel.id}/typing") -) - -// Messages -var ( - GetMessages = NewAPIRoute(GET, "/channels/{channel.id}/messages") - GetMessage = NewAPIRoute(GET, "/channels/{channel.id}/messages/{message.id}") - CreateMessage = NewAPIRoute(POST, "/channels/{channel.id}/messages") - UpdateMessage = NewAPIRoute(PATCH, "/channels/{channel.id}/messages/{message.id}") - DeleteMessage = NewAPIRoute(DELETE, "/channels/{channel.id}/messages/{message.id}") - BulkDeleteMessage = NewAPIRoute(POST, "/channels/{channel.id}/messages/bulk-delete") - - GetPinnedMessages = NewAPIRoute(GET, "/channels/{channel.id}/pins") - AddPinnedMessage = NewAPIRoute(PUT, "/channels/{channel.id}/pins/{message.id}") - RemovePinnedMessage = NewAPIRoute(DELETE, "/channels/{channel.id}/pins/{message.id}") - - CrosspostMessage = NewAPIRoute(POST, "/channels/{channel.id}/messages/{message.id}/crosspost") - - GetReactions = NewAPIRoute(GET, "/channels/{channel.id}/messages/{message.id}/reactions/{emoji}") - AddReaction = NewAPIRoute(PUT, "/channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me") - RemoveOwnReaction = NewAPIRoute(DELETE, "/channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me") - RemoveUserReaction = NewAPIRoute(DELETE, "/channels/{channel.id}/messages/{message.id}/reactions/{emoji}/{user.id}") - RemoveAllReactions = NewAPIRoute(DELETE, "/channels/{channel.id}/messages/{message.id}/reactions") - RemoveAllReactionsEmoji = NewAPIRoute(DELETE, "/channels/{channel.id}/messages/{message.id}/reactions/{emoji}") -) - -// Emotes -var ( - GetEmotes = NewAPIRoute(GET, "/guilds/{guild.id}/emojis") - Getemote = NewAPIRoute(GET, "/guilds/{guild.id}/emojis/{emoji.id}") - CreateEmote = NewAPIRoute(POST, "/guilds/{guild.id}/emojis") - UpdateEmote = NewAPIRoute(PATCH, "/guilds/{guild.id}/emojis/{emote.id}") - DeleteEmote = NewAPIRoute(DELETE, "/guilds/{guild.id}/emojis/{emote.id}") -) - -// Webhooks -var ( - GetWebhook = NewAPIRoute(GET, "/webhooks/{webhook.id}") - GetWebhookWithToken = NewAPIRoute(GET, "/webhooks/{webhook.id}/{token}") - UpdateWebhok = NewAPIRoute(PATCH, "/webhooks/{webhook.id}") - UpdateWebhokWithToken = NewAPIRoute(PATCH, "/webhooks/{webhook.id}/{token}") - DeleteWebhook = NewAPIRoute(DELETE, "/webhooks/{webhook.id}") - DeleteWebhookWithToken = NewAPIRoute(DELETE, "/webhooks/{webhook.id}/{token}") - - CreateWebhookMessage = NewAPIRoute(POST, "/webhooks/{webhook.id}") - CreateWebhookMessageSlack = NewAPIRoute(POST, "/webhooks/{webhook.id}/slack") - CreateWebhookMessageGithub = NewAPIRoute(POST, "/webhooks/{webhook.id}/github") - UpdateWebhookMessage = NewAPIRoute(POST, "/webhooks/{webhook.id}/{token}/messages/{message.id}") - DeleteWebhookMessage = NewAPIRoute(POST, "/webhooks/{webhook.id}/{token}/messages/{message.id}") -) - -// Invites -var ( - GetInvite = NewAPIRoute(GET, "/invites/{code}") - CreateInvite = NewAPIRoute(POST, "/channels/{channel.id}/invites") - DeleteInvite = NewAPIRoute(DELETE, "/invites/{code}") - - GetGuildInvite = NewAPIRoute(GET, "/guilds/{guild.id}/invites") - GetChannelInvites = NewAPIRoute(GET, "/channels/{channel.id}/invites") -) - -// CDN -var ( - Emote = NewCDNRoute("/emojis/{emote.id}.", PNG, GIF) - GuildIcon = NewCDNRoute("/icons/{guild.id}/{icon.hash}.", PNG, JPEG, WEBP, GIF) - GuildSplash = NewCDNRoute("/splashes/{guild.id}/guild.splash.", PNG, JPEG, WEBP) - GuildDiscoverySplash = NewCDNRoute("/discovery-splashes/{guild.id}/guild.discovery.splash.", PNG, JPEG, WEBP) - GuildBanner = NewCDNRoute("/banners/{guild.id}/guild.banner.", PNG, JPEG, WEBP) - DefaultUserAvatar = NewCDNRoute("/embed/avatars/{user.discriminator%5}.", PNG) - UserAvatar = NewCDNRoute("/avatars/{user.id}/user.avatar.", PNG, JPEG, WEBP, GIF) - ApplicationIcon = NewCDNRoute("/app-icons/{application.id}/icon.", PNG, JPEG, WEBP) - ApplicationAsset = NewCDNRoute("/app-assets/{application.id}/{asset.id}.", PNG, JPEG, WEBP) - AchievementIcon = NewCDNRoute("/app-assets/{application.id}/achievements/{achievement.id}/icons/{icon.hash}.", PNG, JPEG, WEBP) - TeamIcon = NewCDNRoute("/team-icons/{team.id}/team.icon.", PNG, JPEG, WEBP) - Attachments = NewCDNRoute("/attachments/{channel.id}/{attachment.id}/{file.name}", BLANK) -) - -// Other -var ( - InviteURL = NewRoute("https://discord.gg/{code}") -) diff --git a/api/endpoints/methods.go b/api/endpoints/methods.go deleted file mode 100644 index 658e8aab..00000000 --- a/api/endpoints/methods.go +++ /dev/null @@ -1,17 +0,0 @@ -package endpoints - -// Method is a HTTP request Method -type Method string - -// HTTP Methods used by Discord -const ( - DELETE Method = "DELETE" - GET Method = "GET" - POST Method = "POST" - PUT Method = "PUT" - PATCH Method = "PATCH" -) - -func (m Method) String() string { - return string(m) -} diff --git a/api/endpoints/route.go b/api/endpoints/route.go deleted file mode 100644 index 771a8e58..00000000 --- a/api/endpoints/route.go +++ /dev/null @@ -1,56 +0,0 @@ -package endpoints - -import ( - "errors" - "fmt" - "strconv" - "strings" -) - -// Route the base struct for routes used in disgo -type Route struct { - baseRoute string - route string - paramCount int -} - -// Compile builds a full request URL based on provided arguments -func (r Route) Compile(args ...interface{}) (*CompiledRoute, error) { - if len(args) != r.paramCount { - return nil, errors.New("invalid amount of arguments received. expected: " + strconv.Itoa(len(args)) + ", received: " + strconv.Itoa(r.paramCount)) - } - route := r.route - if len(args) > 0 { - for _, arg := range args { - start := strings.Index(route, "{") - end := strings.Index(route, "}") - route = route[:start] + fmt.Sprint(arg) + route[end+1:] - } - } - - return &CompiledRoute{route: r.baseRoute + route}, nil -} - -// NewRoute generates a Route when given a URL -func NewRoute(url string) Route { - return Route{ - baseRoute: "", - route: url, - paramCount: countParams(url), - } -} - -func countParams(url string) int { - paramCount := strings.Count(url, "{") - return paramCount -} - -// CompiledRoute is Route compiled with all URL args -type CompiledRoute struct { - route string -} - -// Route returns the full request url -func (r CompiledRoute) Route() string { - return r.route -} diff --git a/api/endpoints/route_test.go b/api/endpoints/route_test.go deleted file mode 100644 index 052238ff..00000000 --- a/api/endpoints/route_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package endpoints - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestAPIRoute_Compile(t *testing.T) { - compiledRoute, err := AddReaction.Compile("test1", "test2", "test3") - assert.NoError(t, err) - assert.Equal(t, API+"/channels/test1/messages/test2/reactions/test3/@me", compiledRoute.Route()) -} - -func TestCDNRoute_Compile(t *testing.T) { - compiledRoute, err := Emote.Compile(PNG, "test1") - assert.NoError(t, err) - assert.Equal(t, CDN+"/emojis/test1.png", compiledRoute.Route()) - - compiledRoute, err = Emote.Compile(GIF, "test1") - assert.NoError(t, err) - assert.Equal(t, CDN+"/emojis/test1.gif", compiledRoute.Route()) -} - -func TestCustomRoute_Compile(t *testing.T) { - testAPI := NewCustomRoute(GET, "https://test.de/{test}") - - compiledRoute, err := testAPI.Compile("test") - assert.NoError(t, err) - assert.Equal(t, "https://test.de/test", compiledRoute.Route()) -} diff --git a/api/guild.go b/api/guild.go index 393d9a83..d56cc3fa 100644 --- a/api/guild.go +++ b/api/guild.go @@ -4,7 +4,7 @@ import ( "strings" "time" - "github.com/DisgoOrg/disgo/api/endpoints" + "github.com/DisgoOrg/restclient" ) // PremiumTier tells you the boost level of a guild @@ -187,16 +187,16 @@ func (g *Guild) AddMember(userID Snowflake, addGuildMemberData *AddGuildMemberDa } // IconURL returns the Icon of a guild_events -func (g *Guild) IconURL() *string { +func (g *Guild) IconURL(size int) *string { if g.Icon == nil { return nil } animated := strings.HasPrefix(*g.Icon, "a_") - format := endpoints.PNG + format := restclient.PNG if animated { - format = endpoints.GIF + format = restclient.GIF } - route, err := endpoints.GuildIcon.Compile(format, g.ID.String(), *g.Icon) + route, err := restclient.GuildIcon.Compile(nil, format, size, g.ID.String(), *g.Icon) if err != nil { return nil } diff --git a/api/invite.go b/api/invite.go index d12396b8..ee579990 100644 --- a/api/invite.go +++ b/api/invite.go @@ -3,7 +3,7 @@ package api import ( "time" - "github.com/DisgoOrg/disgo/api/endpoints" + "github.com/DisgoOrg/restclient" ) // ExpandedInvite is a full Invite struct @@ -31,7 +31,7 @@ type Invite struct { // URL returns the invite url in format like https://discord.gg/{code} func (i Invite) URL() string { - url, err := endpoints.InviteURL.Compile(i.Code) + url, err := restclient.InviteURL.Compile(nil, i.Code) if err != nil { return "" } diff --git a/api/restclient.go b/api/restclient.go index a619cc77..19cbdff5 100644 --- a/api/restclient.go +++ b/api/restclient.go @@ -3,7 +3,7 @@ package api import ( "errors" - "github.com/DisgoOrg/disgo/api/endpoints" + "github.com/DisgoOrg/restclient" ) // Errors when connecting to discord @@ -23,12 +23,10 @@ type ErrorResponse struct { // RestClient is a manager for all of disgo's HTTP requests type RestClient interface { + restclient.RestClient Close() Disgo() Disgo - UserAgent() string - Request(route *endpoints.CompiledAPIRoute, rqBody interface{}, rsBody interface{}) error - SendMessage(channelID Snowflake, message *MessageCreate) (*Message, error) EditMessage(channelID Snowflake, messageID Snowflake, message *MessageUpdate) (*Message, error) DeleteMessage(channelID Snowflake, messageID Snowflake) error diff --git a/api/user.go b/api/user.go index 7c996c24..26200d64 100644 --- a/api/user.go +++ b/api/user.go @@ -5,7 +5,7 @@ import ( "strconv" "strings" - "github.com/DisgoOrg/disgo/api/endpoints" + "github.com/DisgoOrg/restclient" ) // User is a struct for interacting with discord's users @@ -27,20 +27,20 @@ type User struct { } // AvatarURL returns the Avatar URL of the User -func (u *User) AvatarURL() string { +func (u *User) AvatarURL(size int) string { if u.Avatar == nil { discrim, _ := strconv.Atoi(u.Discriminator) - route, err := endpoints.DefaultUserAvatar.Compile(endpoints.PNG, discrim%5) + route, err := restclient.DefaultUserAvatar.Compile(nil, restclient.PNG, size, discrim%5) if err != nil { return "" } return route.Route() } - format := endpoints.PNG + format := restclient.PNG if strings.HasPrefix(*u.Avatar, "a_") { - format = endpoints.GIF + format = restclient.GIF } - route, err := endpoints.UserAvatar.Compile(format, u.ID.String(), *u.Avatar) + route, err := restclient.UserAvatar.Compile(nil, format, size, u.ID.String(), *u.Avatar) if err != nil { return "" } diff --git a/example/go.sum b/example/go.sum index c78d4f6d..d27607c8 100644 --- a/example/go.sum +++ b/example/go.sum @@ -1,5 +1,11 @@ github.com/DisgoOrg/log v1.0.3 h1:IjmZQQu/kuBIui22EdXmxzQGYwcPCJEkXa0Fe6W9fJk= github.com/DisgoOrg/log v1.0.3/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= +github.com/DisgoOrg/restclient v1.1.1 h1:xjDPlbS5yXSnQuL7cxgcm9Zyo0FWT4yDVkpn9gvC+dI= +github.com/DisgoOrg/restclient v1.1.1/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= +github.com/DisgoOrg/restclient v1.1.2 h1:KxpWL3t587EFjfwELVsWVrEeoBIQCcKXCTEBffCDKrI= +github.com/DisgoOrg/restclient v1.1.2/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= +github.com/DisgoOrg/restclient v1.1.3 h1:ZspV/tSwzCSffIZMRctS+ryzKmgNrKEqKMH6UQW819A= +github.com/DisgoOrg/restclient v1.1.3/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= github.com/PaesslerAG/gval v1.1.0 h1:k3RuxeZDO3eejD4cMPSt+74tUSvTnbGvLx0df4mdwFc= github.com/PaesslerAG/gval v1.1.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= diff --git a/go.mod b/go.mod index 460f2c3c..80409f86 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/DisgoOrg/log v1.0.3 + github.com/DisgoOrg/restclient v1.1.3 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index 7fd0a7b8..32ffdfd5 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/DisgoOrg/log v1.0.3 h1:IjmZQQu/kuBIui22EdXmxzQGYwcPCJEkXa0Fe6W9fJk= github.com/DisgoOrg/log v1.0.3/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= +github.com/DisgoOrg/restclient v1.1.3 h1:ZspV/tSwzCSffIZMRctS+ryzKmgNrKEqKMH6UQW819A= +github.com/DisgoOrg/restclient v1.1.3/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= diff --git a/internal/gateway_impl.go b/internal/gateway_impl.go index 1f5478db..8ba97913 100644 --- a/internal/gateway_impl.go +++ b/internal/gateway_impl.go @@ -14,7 +14,7 @@ import ( "github.com/gorilla/websocket" "github.com/DisgoOrg/disgo/api" - "github.com/DisgoOrg/disgo/api/endpoints" + "github.com/DisgoOrg/restclient" ) func newGatewayImpl(disgo api.Disgo) api.Gateway { @@ -73,17 +73,17 @@ func (g *GatewayImpl) Open() error { if g.url == nil { g.Disgo().Logger().Debug("gateway url empty, fetching...") gatewayRs := api.GatewayRs{} - compiledRoute, err := endpoints.GetGateway.Compile() + compiledRoute, err := restclient.GetGateway.Compile(nil) if err != nil { return err } - if err = g.Disgo().RestClient().Request(compiledRoute, nil, &gatewayRs); err != nil { + if err = g.Disgo().RestClient().Do(compiledRoute, nil, &gatewayRs); err != nil { return err } g.url = &gatewayRs.URL } - gatewayURL := *g.url + "?v=" + endpoints.APIVersion + "&encoding=json" + gatewayURL := *g.url + "?v=" + restclient.APIVersion + "&encoding=json" wsConn, rs, err := websocket.DefaultDialer.Dial(gatewayURL, nil) if err != nil { g.Close() diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index 17aa0fdf..8090960e 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -1,164 +1,68 @@ package internal import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" "net/http" - "net/url" "strings" - "github.com/DisgoOrg/disgo/api/events" - "github.com/DisgoOrg/disgo/api" - "github.com/DisgoOrg/disgo/api/endpoints" + "github.com/DisgoOrg/restclient" ) -func newRestClientImpl(disgo api.Disgo, client *http.Client) api.RestClient { - if client == nil { - client = http.DefaultClient +func newRestClientImpl(disgo api.Disgo, httpClient *http.Client) api.RestClient { + if httpClient == nil { + httpClient = http.DefaultClient } return &RestClientImpl{ - disgo: disgo, - client: client, + RestClient: restclient.NewRestClient(httpClient, disgo.Logger(), "DiscordBot (https://github.com/disgoorg/disgo, 0.0.1)", http.Header{"Authorization": []string{"Bot " + disgo.Token()}}), + disgo: disgo, } } // RestClientImpl is the rest client implementation used for HTTP requests to discord type RestClientImpl struct { - disgo api.Disgo - client *http.Client - token string + restclient.RestClient + disgo api.Disgo } // Disgo returns the api.Disgo instance -func (r RestClientImpl) Disgo() api.Disgo { +func (r *RestClientImpl) Disgo() api.Disgo { return r.disgo } -// Client returns the http.Client used by this api.RestClient -func (r RestClientImpl) Client() *http.Client { - return r.client -} - // Close cleans up the http managers connections -func (r RestClientImpl) Close() { - r.client.CloseIdleConnections() -} - -// UserAgent returns the user agent for this api.RestClient -func (r RestClientImpl) UserAgent() string { - return "DiscordBot (https://github.com/disgoorg/disgo, 0.0.1)" -} - -// Request makes a new rest request to discords api with the specific endpoints.APIRoute -func (r RestClientImpl) Request(route *endpoints.CompiledAPIRoute, rqBody interface{}, rsBody interface{}) error { - var reader io.Reader - var rqJSON []byte - var contentType string - if rqBody != nil { - switch v := rqBody.(type) { - case url.Values: - contentType = "application/x-www-form-urlencoded" - rqJSON = []byte(v.Encode()) - default: - contentType = "application/json" - var err error - rqJSON, err = json.Marshal(rqBody) - if err != nil { - return err - } - } - r.Disgo().Logger().Debugf("request body: \"%s\"", string(rqJSON)) - reader = bytes.NewBuffer(rqJSON) - } else { - reader = nil - } - - rq, err := http.NewRequest(route.Method().String(), route.Route(), reader) - if err != nil { - return err - } - rq.Header.Set("User-Agent", r.UserAgent()) - rq.Header.Set("Authorization", "Bot "+r.disgo.Token()) - rq.Header.Set("Content-Type", contentType) - - rs, err := r.client.Do(rq) - if err != nil { - return err - } - - defer func() { - err = rs.Body.Close() - if err != nil { - r.Disgo().Logger().Error("error closing response body", err.Error()) - } - }() - - rawRsBody, err := ioutil.ReadAll(rs.Body) - if err != nil { - r.Disgo().Logger().Errorf("error reading from response body: %s", err) - return err - } - - r.Disgo().Logger().Debugf("code: %d, response: %s", rs.StatusCode, string(rawRsBody)) +func (r *RestClientImpl) Close() { + r.HttpClient().CloseIdleConnections() +} - r.Disgo().EventManager().Dispatch(events.HTTPRequestEvent{ +func (r *RestClientImpl) DoWithHeaders(route *restclient.CompiledAPIRoute, rqBody interface{}, rsBody interface{}, customHeader http.Header) (err restclient.RestError) { + err = r.RestClient.DoWithHeaders(route, rqBody, rsBody, customHeader) + // TODO reimplement events.HTTPRequestEvent + /*r.Disgo().EventManager().Dispatch(events.HTTPRequestEvent{ GenericEvent: events.NewEvent(r.Disgo(), 0), Request: rq, Response: rs, - }) + }) */ - switch rs.StatusCode { - case http.StatusOK, http.StatusCreated, http.StatusNoContent: - if rsBody != nil { - if err = json.Unmarshal(rawRsBody, rsBody); err != nil { - r.Disgo().Logger().Errorf("error unmarshalling response. error: %s", err) + // TODO reimplement api.ErrorResponse unmarshalling + /* + var errorRs api.ErrorResponse + if err = json.Unmarshal(rawRsBody, &errorRs); err != nil { + r.Disgo().Logger().Errorf("error unmarshalling error response. code: %d, error: %s", rs.StatusCode, err) return err } - } - return nil - - case http.StatusTooManyRequests: - limit := rs.Header.Get("X-RateLimit-Limit") - remaining := rs.Header.Get("X-RateLimit-Limit") - reset := rs.Header.Get("X-RateLimit-Limit") - bucket := rs.Header.Get("X-RateLimit-Limit") - r.Disgo().Logger().Errorf("too many requests. limit: %s, remaining: %s, reset: %s,bucket: %s", limit, remaining, reset, bucket) - return api.ErrRatelimited - - case http.StatusBadGateway: - r.Disgo().Logger().Error(api.ErrBadGateway) - return api.ErrBadGateway - - case http.StatusBadRequest: - r.Disgo().Logger().Errorf("bad request request: \"%s\", response: \"%s\"", string(rqJSON), string(rawRsBody)) - return api.ErrBadRequest - - case http.StatusUnauthorized: - r.Disgo().Logger().Error(api.ErrUnauthorized) - return api.ErrUnauthorized - - default: - var errorRs api.ErrorResponse - if err = json.Unmarshal(rawRsBody, &errorRs); err != nil { - r.Disgo().Logger().Errorf("error unmarshalling error response. code: %d, error: %s", rs.StatusCode, err) - return err - } - return fmt.Errorf("request to %s failed. statuscode: %d, errorcode: %d, message_events: %s", rq.URL, rs.StatusCode, errorRs.Code, errorRs.Message) - } + return fmt.Errorf("request to %s failed. statuscode: %d, errorcode: %d, message_events: %s", rq.URL, rs.StatusCode, errorRs.Code, errorRs.Message) + */ + return } // SendMessage lets you send a api.Message to a api.MessageChannel -func (r RestClientImpl) SendMessage(channelID api.Snowflake, message *api.MessageCreate) (msg *api.Message, err error) { - compiledRoute, err := endpoints.CreateMessage.Compile(channelID) +func (r *RestClientImpl) SendMessage(channelID api.Snowflake, message *api.MessageCreate) (msg *api.Message, err error) { + compiledRoute, err := restclient.CreateMessage.Compile(nil, channelID) if err != nil { return nil, err } var fullMsg *api.FullMessage - err = r.Request(compiledRoute, message, &fullMsg) + err = r.Do(compiledRoute, message, &fullMsg) if err == nil { msg = r.Disgo().EntityBuilder().CreateMessage(fullMsg, api.CacheStrategyNoWs) } @@ -166,13 +70,13 @@ func (r RestClientImpl) SendMessage(channelID api.Snowflake, message *api.Messag } // EditMessage lets you edit a api.Message -func (r RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowflake, message *api.MessageUpdate) (msg *api.Message, err error) { - compiledRoute, err := endpoints.UpdateMessage.Compile(channelID, messageID) +func (r *RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowflake, message *api.MessageUpdate) (msg *api.Message, err error) { + compiledRoute, err := restclient.UpdateMessage.Compile(nil, channelID, messageID) if err != nil { return nil, err } var fullMsg *api.FullMessage - err = r.Request(compiledRoute, message, &fullMsg) + err = r.Do(compiledRoute, message, &fullMsg) if err == nil { msg = r.Disgo().EntityBuilder().CreateMessage(fullMsg, api.CacheStrategyNoWs) } @@ -180,12 +84,12 @@ func (r RestClientImpl) EditMessage(channelID api.Snowflake, messageID api.Snowf } // DeleteMessage lets you delete a api.Message -func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Snowflake) (err error) { - compiledRoute, err := endpoints.DeleteMessage.Compile(channelID, messageID) +func (r *RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Snowflake) (err error) { + compiledRoute, err := restclient.DeleteMessage.Compile(nil, channelID, messageID) if err != nil { return err } - err = r.Request(compiledRoute, nil, nil) + err = r.Do(compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheMessage(channelID, messageID) } @@ -193,12 +97,12 @@ func (r RestClientImpl) DeleteMessage(channelID api.Snowflake, messageID api.Sno } // BulkDeleteMessages lets you bulk delete api.Message(s) -func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs ...api.Snowflake) (err error) { - compiledRoute, err := endpoints.BulkDeleteMessage.Compile(channelID) +func (r *RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs ...api.Snowflake) (err error) { + compiledRoute, err := restclient.BulkDeleteMessage.Compile(nil, channelID) if err != nil { return err } - err = r.Request(compiledRoute, api.MessageBulkDelete{Messages: messageIDs}, nil) + err = r.Do(compiledRoute, api.MessageBulkDelete{Messages: messageIDs}, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { // TODO: check here if no err means all messages deleted for _, messageID := range messageIDs { @@ -209,13 +113,13 @@ func (r RestClientImpl) BulkDeleteMessages(channelID api.Snowflake, messageIDs . } // CrosspostMessage lets you crosspost a api.Message in a channel with type api.ChannelTypeNews -func (r RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api.Snowflake) (msg *api.Message, err error) { - compiledRoute, err := endpoints.CrosspostMessage.Compile(channelID, messageID) +func (r *RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api.Snowflake) (msg *api.Message, err error) { + compiledRoute, err := restclient.CrosspostMessage.Compile(nil, channelID, messageID) if err != nil { return nil, err } var fullMsg *api.FullMessage - err = r.Request(compiledRoute, nil, &fullMsg) + err = r.Do(compiledRoute, nil, &fullMsg) if err == nil { msg = r.Disgo().EntityBuilder().CreateMessage(fullMsg, api.CacheStrategyNoWs) } @@ -223,8 +127,8 @@ func (r RestClientImpl) CrosspostMessage(channelID api.Snowflake, messageID api. } // OpenDMChannel opens a new dm channel a user -func (r RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChannel, err error) { - compiledRoute, err := endpoints.CreateDMChannel.Compile() +func (r *RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChannel, err error) { + compiledRoute, err := restclient.CreateDMChannel.Compile(nil) if err != nil { return nil, err } @@ -233,7 +137,7 @@ func (r RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChan }{ RecipientID: userID, } - err = r.Request(compiledRoute, body, &channel) + err = r.Do(compiledRoute, body, &channel) if err == nil { channel = r.Disgo().EntityBuilder().CreateDMChannel(&channel.MessageChannel.Channel, api.CacheStrategyNoWs) } @@ -241,13 +145,13 @@ func (r RestClientImpl) OpenDMChannel(userID api.Snowflake) (channel *api.DMChan } // UpdateSelfNick updates the bots nickname in a guild -func (r RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (newNick *string, err error) { - compiledRoute, err := endpoints.UpdateSelfNick.Compile(guildID) +func (r *RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (newNick *string, err error) { + compiledRoute, err := restclient.UpdateSelfNick.Compile(nil, guildID) if err != nil { return nil, err } var updateNick *api.UpdateSelfNick - err = r.Request(compiledRoute, &api.UpdateSelfNick{Nick: nick}, &updateNick) + err = r.Do(compiledRoute, &api.UpdateSelfNick{Nick: nick}, &updateNick) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().Member(guildID, r.Disgo().ApplicationID()).Nick = updateNick.Nick newNick = updateNick.Nick @@ -256,12 +160,12 @@ func (r RestClientImpl) UpdateSelfNick(guildID api.Snowflake, nick *string) (new } // GetUser fetches the specific user -func (r RestClientImpl) GetUser(userID api.Snowflake) (user *api.User, err error) { - compiledRoute, err := endpoints.GetUser.Compile(userID) +func (r *RestClientImpl) GetUser(userID api.Snowflake) (user *api.User, err error) { + compiledRoute, err := restclient.GetUser.Compile(nil, userID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &user) + err = r.Do(compiledRoute, nil, &user) if err == nil { user = r.Disgo().EntityBuilder().CreateUser(user, api.CacheStrategyNoWs) } @@ -269,12 +173,12 @@ func (r RestClientImpl) GetUser(userID api.Snowflake) (user *api.User, err error } // GetMember fetches the specific member -func (r RestClientImpl) GetMember(guildID api.Snowflake, userID api.Snowflake) (member *api.Member, err error) { - compiledRoute, err := endpoints.GetMember.Compile(guildID, userID) +func (r *RestClientImpl) GetMember(guildID api.Snowflake, userID api.Snowflake) (member *api.Member, err error) { + compiledRoute, err := restclient.GetMember.Compile(nil, guildID, userID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &member) + err = r.Do(compiledRoute, nil, &member) if err == nil { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } @@ -282,12 +186,12 @@ func (r RestClientImpl) GetMember(guildID api.Snowflake, userID api.Snowflake) ( } // GetMembers fetches all members for a guild -func (r RestClientImpl) GetMembers(guildID api.Snowflake) (members []*api.Member, err error) { - compiledRoute, err := endpoints.GetMembers.Compile(guildID) +func (r *RestClientImpl) GetMembers(guildID api.Snowflake) (members []*api.Member, err error) { + compiledRoute, err := restclient.GetMembers.Compile(nil, guildID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &members) + err = r.Do(compiledRoute, nil, &members) if err == nil { for _, member := range members { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) @@ -297,12 +201,12 @@ func (r RestClientImpl) GetMembers(guildID api.Snowflake) (members []*api.Member } // AddMember adds a member to the guild with the oauth2 access BotToken. requires api.PermissionCreateInstantInvite -func (r RestClientImpl) AddMember(guildID api.Snowflake, userID api.Snowflake, addGuildMemberData *api.AddGuildMemberData) (member *api.Member, err error) { - compiledRoute, err := endpoints.AddMember.Compile(guildID, userID) +func (r *RestClientImpl) AddMember(guildID api.Snowflake, userID api.Snowflake, addGuildMemberData *api.AddGuildMemberData) (member *api.Member, err error) { + compiledRoute, err := restclient.AddMember.Compile(nil, guildID, userID) if err != nil { return nil, err } - err = r.Request(compiledRoute, addGuildMemberData, &member) + err = r.Do(compiledRoute, addGuildMemberData, &member) if err == nil { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } @@ -310,17 +214,17 @@ func (r RestClientImpl) AddMember(guildID api.Snowflake, userID api.Snowflake, a } // KickMember kicks a member from the guild. requires api.PermissionKickMembers -func (r RestClientImpl) KickMember(guildID api.Snowflake, userID api.Snowflake, reason *string) (err error) { - var compiledRoute *endpoints.CompiledAPIRoute - if reason == nil { - compiledRoute, err = endpoints.RemoveMember.Compile(guildID, userID) - } else { - compiledRoute, err = endpoints.RemoveMemberReason.Compile(guildID, userID, *reason) +func (r *RestClientImpl) KickMember(guildID api.Snowflake, userID api.Snowflake, reason *string) (err error) { + var compiledRoute *restclient.CompiledAPIRoute + var params map[string]interface{} + if reason != nil { + params = map[string]interface{}{"reason": *reason} } + compiledRoute, err = restclient.RemoveMember.Compile(params, guildID, userID) if err != nil { return } - err = r.Request(compiledRoute, nil, nil) + err = r.Do(compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheMember(guildID, userID) } @@ -328,12 +232,12 @@ func (r RestClientImpl) KickMember(guildID api.Snowflake, userID api.Snowflake, } // UpdateMember updates a member -func (r RestClientImpl) UpdateMember(guildID api.Snowflake, userID api.Snowflake, updateGuildMemberData *api.UpdateGuildMemberData) (member *api.Member, err error) { - compiledRoute, err := endpoints.UpdateMember.Compile(guildID, userID) +func (r *RestClientImpl) UpdateMember(guildID api.Snowflake, userID api.Snowflake, updateGuildMemberData *api.UpdateGuildMemberData) (member *api.Member, err error) { + compiledRoute, err := restclient.UpdateMember.Compile(nil, guildID, userID) if err != nil { return nil, err } - err = r.Request(compiledRoute, updateGuildMemberData, &member) + err = r.Do(compiledRoute, updateGuildMemberData, &member) if err == nil { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } @@ -341,12 +245,12 @@ func (r RestClientImpl) UpdateMember(guildID api.Snowflake, userID api.Snowflake } // MoveMember moves/kicks the member to/from a voice channel -func (r RestClientImpl) MoveMember(guildID api.Snowflake, userID api.Snowflake, channelID *api.Snowflake) (member *api.Member, err error) { - compiledRoute, err := endpoints.UpdateMember.Compile(guildID, userID) +func (r *RestClientImpl) MoveMember(guildID api.Snowflake, userID api.Snowflake, channelID *api.Snowflake) (member *api.Member, err error) { + compiledRoute, err := restclient.UpdateMember.Compile(nil, guildID, userID) if err != nil { return nil, err } - err = r.Request(compiledRoute, api.MoveGuildMemberData{ChannelID: channelID}, &member) + err = r.Do(compiledRoute, api.MoveGuildMemberData{ChannelID: channelID}, &member) if err == nil { member = r.Disgo().EntityBuilder().CreateMember(guildID, member, api.CacheStrategyNoWs) } @@ -354,12 +258,12 @@ func (r RestClientImpl) MoveMember(guildID api.Snowflake, userID api.Snowflake, } // AddMemberRole adds a role to a member -func (r RestClientImpl) AddMemberRole(guildID api.Snowflake, userID api.Snowflake, roleID api.Snowflake) (err error) { - compiledRoute, err := endpoints.AddMemberRole.Compile(guildID, userID, roleID) +func (r *RestClientImpl) AddMemberRole(guildID api.Snowflake, userID api.Snowflake, roleID api.Snowflake) (err error) { + compiledRoute, err := restclient.AddMemberRole.Compile(nil, guildID, userID, roleID) if err != nil { return err } - err = r.Request(compiledRoute, nil, nil) + err = r.Do(compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { member := r.Disgo().Cache().Member(guildID, userID) if member != nil { @@ -370,12 +274,12 @@ func (r RestClientImpl) AddMemberRole(guildID api.Snowflake, userID api.Snowflak } // RemoveMemberRole removes a role from a member -func (r RestClientImpl) RemoveMemberRole(guildID api.Snowflake, userID api.Snowflake, roleID api.Snowflake) (err error) { - compiledRoute, err := endpoints.RemoveMemberRole.Compile(guildID, userID, roleID) +func (r *RestClientImpl) RemoveMemberRole(guildID api.Snowflake, userID api.Snowflake, roleID api.Snowflake) (err error) { + compiledRoute, err := restclient.RemoveMemberRole.Compile(nil, guildID, userID, roleID) if err != nil { return err } - err = r.Request(compiledRoute, nil, nil) + err = r.Do(compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { member := r.Disgo().Cache().Member(guildID, userID) if member != nil { @@ -391,12 +295,12 @@ func (r RestClientImpl) RemoveMemberRole(guildID api.Snowflake, userID api.Snowf } // GetRoles fetches all roles from a guild -func (r RestClientImpl) GetRoles(guildID api.Snowflake) (roles []*api.Role, err error) { - compiledRoute, err := endpoints.GetRoles.Compile(guildID) +func (r *RestClientImpl) GetRoles(guildID api.Snowflake) (roles []*api.Role, err error) { + compiledRoute, err := restclient.GetRoles.Compile(nil, guildID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &roles) + err = r.Do(compiledRoute, nil, &roles) if err == nil { for _, role := range roles { role = r.Disgo().EntityBuilder().CreateRole(guildID, role, api.CacheStrategyNoWs) @@ -406,12 +310,12 @@ func (r RestClientImpl) GetRoles(guildID api.Snowflake) (roles []*api.Role, err } // CreateRole creates a new role for a guild. Requires api.PermissionManageRoles -func (r RestClientImpl) CreateRole(guildID api.Snowflake, role *api.UpdateRole) (newRole *api.Role, err error) { - compiledRoute, err := endpoints.CreateRole.Compile(guildID) +func (r *RestClientImpl) CreateRole(guildID api.Snowflake, role *api.UpdateRole) (newRole *api.Role, err error) { + compiledRoute, err := restclient.CreateRole.Compile(nil, guildID) if err != nil { return nil, err } - err = r.Request(compiledRoute, role, &newRole) + err = r.Do(compiledRoute, role, &newRole) if err == nil { newRole = r.Disgo().EntityBuilder().CreateRole(guildID, newRole, api.CacheStrategyNoWs) } @@ -419,12 +323,12 @@ func (r RestClientImpl) CreateRole(guildID api.Snowflake, role *api.UpdateRole) } // UpdateRole updates a role from a guild. Requires api.PermissionManageRoles -func (r RestClientImpl) UpdateRole(guildID api.Snowflake, roleID api.Snowflake, role *api.UpdateRole) (newRole *api.Role, err error) { - compiledRoute, err := endpoints.UpdateRole.Compile(guildID, roleID) +func (r *RestClientImpl) UpdateRole(guildID api.Snowflake, roleID api.Snowflake, role *api.UpdateRole) (newRole *api.Role, err error) { + compiledRoute, err := restclient.UpdateRole.Compile(nil, guildID, roleID) if err != nil { return nil, err } - err = r.Request(compiledRoute, role, &newRole) + err = r.Do(compiledRoute, role, &newRole) if err == nil { newRole = r.Disgo().EntityBuilder().CreateRole(guildID, newRole, api.CacheStrategyNoWs) } @@ -432,12 +336,12 @@ func (r RestClientImpl) UpdateRole(guildID api.Snowflake, roleID api.Snowflake, } // UpdateRolePositions updates the position of a role from a guild. Requires api.PermissionManageRoles -func (r RestClientImpl) UpdateRolePositions(guildID api.Snowflake, roleUpdates ...*api.UpdateRolePosition) (roles []*api.Role, err error) { - compiledRoute, err := endpoints.GetRoles.Compile(guildID) +func (r *RestClientImpl) UpdateRolePositions(guildID api.Snowflake, roleUpdates ...*api.UpdateRolePosition) (roles []*api.Role, err error) { + compiledRoute, err := restclient.GetRoles.Compile(nil, guildID) if err != nil { return nil, err } - err = r.Request(compiledRoute, roleUpdates, &roles) + err = r.Do(compiledRoute, roleUpdates, &roles) if err == nil { for _, role := range roles { role = r.Disgo().EntityBuilder().CreateRole(guildID, role, api.CacheStrategyNoWs) @@ -447,12 +351,12 @@ func (r RestClientImpl) UpdateRolePositions(guildID api.Snowflake, roleUpdates . } // DeleteRole deletes a role from a guild. Requires api.PermissionManageRoles -func (r RestClientImpl) DeleteRole(guildID api.Snowflake, roleID api.Snowflake) (err error) { - compiledRoute, err := endpoints.UpdateRole.Compile(guildID, roleID) +func (r *RestClientImpl) DeleteRole(guildID api.Snowflake, roleID api.Snowflake) (err error) { + compiledRoute, err := restclient.UpdateRole.Compile(nil, guildID, roleID) if err != nil { return err } - err = r.Request(compiledRoute, nil, nil) + err = r.Do(compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.disgo.Cache().UncacheRole(guildID, roleID) } @@ -460,39 +364,39 @@ func (r RestClientImpl) DeleteRole(guildID api.Snowflake, roleID api.Snowflake) } // AddReaction lets you add a reaction to a message_events -func (r RestClientImpl) AddReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string) error { - compiledRoute, err := endpoints.AddReaction.Compile(channelID, messageID, normalizeEmoji(emoji)) +func (r *RestClientImpl) AddReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string) error { + compiledRoute, err := restclient.AddReaction.Compile(nil, channelID, messageID, normalizeEmoji(emoji)) if err != nil { return err } - return r.Request(compiledRoute, nil, nil) + return r.Do(compiledRoute, nil, nil) } // RemoveOwnReaction lets you remove your own reaction from a message_events -func (r RestClientImpl) RemoveOwnReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string) error { - compiledRoute, err := endpoints.RemoveOwnReaction.Compile(channelID, messageID, normalizeEmoji(emoji)) +func (r *RestClientImpl) RemoveOwnReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string) error { + compiledRoute, err := restclient.RemoveOwnReaction.Compile(nil, channelID, messageID, normalizeEmoji(emoji)) if err != nil { return err } - return r.Request(compiledRoute, nil, nil) + return r.Do(compiledRoute, nil, nil) } // RemoveUserReaction lets you remove a specific reaction from a user from a message_events -func (r RestClientImpl) RemoveUserReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string, userID api.Snowflake) error { - compiledRoute, err := endpoints.RemoveUserReaction.Compile(channelID, messageID, normalizeEmoji(emoji), userID) +func (r *RestClientImpl) RemoveUserReaction(channelID api.Snowflake, messageID api.Snowflake, emoji string, userID api.Snowflake) error { + compiledRoute, err := restclient.RemoveUserReaction.Compile(nil, channelID, messageID, normalizeEmoji(emoji), userID) if err != nil { return err } - return r.Request(compiledRoute, nil, nil) + return r.Do(compiledRoute, nil, nil) } // GetGlobalCommands gets you all global commands -func (r RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands []*api.Command, err error) { - compiledRoute, err := endpoints.GetGlobalCommands.Compile(applicationID) +func (r *RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands []*api.Command, err error) { + compiledRoute, err := restclient.GetGlobalCommands.Compile(nil, applicationID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &commands) + err = r.Do(compiledRoute, nil, &commands) if err == nil { for _, cmd := range commands { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) @@ -502,12 +406,12 @@ func (r RestClientImpl) GetGlobalCommands(applicationID api.Snowflake) (commands } // GetGlobalCommand gets you a specific global global command -func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (cmd *api.Command, err error) { - compiledRoute, err := endpoints.GetGlobalCommand.Compile(applicationID, commandID) +func (r *RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (cmd *api.Command, err error) { + compiledRoute, err := restclient.GetGlobalCommand.Compile(nil, applicationID, commandID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &cmd) + err = r.Do(compiledRoute, nil, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } @@ -515,12 +419,12 @@ func (r RestClientImpl) GetGlobalCommand(applicationID api.Snowflake, commandID } // CreateGlobalCommand lets you create a new global command -func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command *api.CommandCreate) (cmd *api.Command, err error) { - compiledRoute, err := endpoints.CreateGlobalCommand.Compile(applicationID) +func (r *RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command *api.CommandCreate) (cmd *api.Command, err error) { + compiledRoute, err := restclient.CreateGlobalCommand.Compile(nil, applicationID) if err != nil { return nil, err } - err = r.Request(compiledRoute, command, &cmd) + err = r.Do(compiledRoute, command, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } @@ -528,8 +432,8 @@ func (r RestClientImpl) CreateGlobalCommand(applicationID api.Snowflake, command } // SetGlobalCommands lets you override all global commands -func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands ...*api.CommandCreate) (cmds []*api.Command, err error) { - compiledRoute, err := endpoints.SetGlobalCommands.Compile(applicationID) +func (r *RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands ...*api.CommandCreate) (cmds []*api.Command, err error) { + compiledRoute, err := restclient.SetGlobalCommands.Compile(nil, applicationID) if err != nil { return nil, err } @@ -537,7 +441,7 @@ func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands err = api.ErrTooMuchCommands return } - err = r.Request(compiledRoute, commands, &cmds) + err = r.Do(compiledRoute, commands, &cmds) if err == nil { for _, cmd := range cmds { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) @@ -547,12 +451,12 @@ func (r RestClientImpl) SetGlobalCommands(applicationID api.Snowflake, commands } // EditGlobalCommand lets you edit a specific global command -func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command *api.CommandUpdate) (cmd *api.Command, err error) { - compiledRoute, err := endpoints.EditGlobalCommand.Compile(applicationID, commandID) +func (r *RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake, command *api.CommandUpdate) (cmd *api.Command, err error) { + compiledRoute, err := restclient.UpdateGlobalCommand.Compile(nil, applicationID, commandID) if err != nil { return nil, err } - err = r.Request(compiledRoute, command, &cmd) + err = r.Do(compiledRoute, command, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGlobalCommand(cmd, api.CacheStrategyNoWs) } @@ -560,12 +464,12 @@ func (r RestClientImpl) EditGlobalCommand(applicationID api.Snowflake, commandID } // DeleteGlobalCommand lets you delete a specific global command -func (r RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (err error) { - compiledRoute, err := endpoints.DeleteGlobalCommand.Compile(applicationID, commandID) +func (r *RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, commandID api.Snowflake) (err error) { + compiledRoute, err := restclient.DeleteGlobalCommand.Compile(nil, applicationID, commandID) if err != nil { return err } - err = r.Request(compiledRoute, nil, nil) + err = r.Do(compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheCommand(commandID) } @@ -573,12 +477,12 @@ func (r RestClientImpl) DeleteGlobalCommand(applicationID api.Snowflake, command } // GetGuildCommands gets you all guild_events commands -func (r RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake) (commands []*api.Command, err error) { - compiledRoute, err := endpoints.GetGuildCommands.Compile(applicationID, guildID) +func (r *RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake) (commands []*api.Command, err error) { + compiledRoute, err := restclient.GetGuildCommands.Compile(nil, applicationID, guildID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &commands) + err = r.Do(compiledRoute, nil, &commands) if err == nil { for _, cmd := range commands { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) @@ -588,12 +492,12 @@ func (r RestClientImpl) GetGuildCommands(applicationID api.Snowflake, guildID ap } // CreateGuildCommand lets you create a new guild_events command -func (r RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, command *api.CommandCreate) (cmd *api.Command, err error) { - compiledRoute, err := endpoints.CreateGuildCommand.Compile(applicationID, guildID) +func (r *RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, command *api.CommandCreate) (cmd *api.Command, err error) { + compiledRoute, err := restclient.CreateGuildCommand.Compile(nil, applicationID, guildID) if err != nil { return nil, err } - err = r.Request(compiledRoute, command, &cmd) + err = r.Do(compiledRoute, command, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } @@ -601,8 +505,8 @@ func (r RestClientImpl) CreateGuildCommand(applicationID api.Snowflake, guildID } // SetGuildCommands lets you override all guild_events commands -func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake, commands ...*api.CommandCreate) (cmds []*api.Command, err error) { - compiledRoute, err := endpoints.SetGuildCommands.Compile(applicationID, guildID) +func (r *RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID api.Snowflake, commands ...*api.CommandCreate) (cmds []*api.Command, err error) { + compiledRoute, err := restclient.SetGuildCommands.Compile(nil, applicationID, guildID) if err != nil { return nil, err } @@ -610,7 +514,7 @@ func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID ap err = api.ErrTooMuchCommands return } - err = r.Request(compiledRoute, commands, &cmds) + err = r.Do(compiledRoute, commands, &cmds) if err == nil { for _, cmd := range cmds { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) @@ -620,12 +524,12 @@ func (r RestClientImpl) SetGuildCommands(applicationID api.Snowflake, guildID ap } // GetGuildCommand gets you a specific guild_events command -func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (cmd *api.Command, err error) { - compiledRoute, err := endpoints.GetGuildCommand.Compile(applicationID, guildID, commandID) +func (r *RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (cmd *api.Command, err error) { + compiledRoute, err := restclient.GetGuildCommand.Compile(nil, applicationID, guildID, commandID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &cmd) + err = r.Do(compiledRoute, nil, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } @@ -633,12 +537,12 @@ func (r RestClientImpl) GetGuildCommand(applicationID api.Snowflake, guildID api } // EditGuildCommand lets you edit a specific guild_events command -func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command *api.CommandUpdate) (cmd *api.Command, err error) { - compiledRoute, err := endpoints.EditGuildCommand.Compile(applicationID, guildID, commandID) +func (r *RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, command *api.CommandUpdate) (cmd *api.Command, err error) { + compiledRoute, err := restclient.UpdateGuildCommand.Compile(nil, applicationID, guildID, commandID) if err != nil { return nil, err } - err = r.Request(compiledRoute, command, &cmd) + err = r.Do(compiledRoute, command, &cmd) if err == nil { cmd = r.Disgo().EntityBuilder().CreateGuildCommand(guildID, cmd, api.CacheStrategyNoWs) } @@ -646,12 +550,12 @@ func (r RestClientImpl) EditGuildCommand(applicationID api.Snowflake, guildID ap } // DeleteGuildCommand lets you delete a specific guild_events command -func (r RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (err error) { - compiledRoute, err := endpoints.DeleteGuildCommand.Compile(applicationID, guildID, commandID) +func (r *RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (err error) { + compiledRoute, err := restclient.DeleteGuildCommand.Compile(nil, applicationID, guildID, commandID) if err != nil { return err } - err = r.Request(compiledRoute, nil, nil) + err = r.Do(compiledRoute, nil, nil) if err == nil && api.CacheStrategyNoWs(r.Disgo()) { r.Disgo().Cache().UncacheCommand(commandID) } @@ -659,12 +563,12 @@ func (r RestClientImpl) DeleteGuildCommand(applicationID api.Snowflake, guildID } // GetGuildCommandsPermissions returns the api.CommandPermission for a all api.Command(s) in a guild -func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake) (cmdsPerms []*api.GuildCommandPermissions, err error) { - compiledRoute, err := endpoints.GetGuildCommandPermissions.Compile(applicationID, guildID) +func (r *RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake) (cmdsPerms []*api.GuildCommandPermissions, err error) { + compiledRoute, err := restclient.GetGuildCommandPermissions.Compile(nil, applicationID, guildID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &cmdsPerms) + err = r.Do(compiledRoute, nil, &cmdsPerms) if err == nil { for _, cmdPerms := range cmdsPerms { cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) @@ -674,12 +578,12 @@ func (r RestClientImpl) GetGuildCommandsPermissions(applicationID api.Snowflake, } // GetGuildCommandPermissions returns the api.CommandPermission for a specific api.Command in a guild -func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (cmdPerms *api.GuildCommandPermissions, err error) { - compiledRoute, err := endpoints.GetGuildCommandPermission.Compile(applicationID, guildID, commandID) +func (r *RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake) (cmdPerms *api.GuildCommandPermissions, err error) { + compiledRoute, err := restclient.GetGuildCommandPermission.Compile(nil, applicationID, guildID, commandID) if err != nil { return nil, err } - err = r.Request(compiledRoute, nil, &cmdPerms) + err = r.Do(compiledRoute, nil, &cmdPerms) if err == nil { cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) } @@ -687,12 +591,12 @@ func (r RestClientImpl) GetGuildCommandPermissions(applicationID api.Snowflake, } // SetGuildCommandsPermissions sets the api.GuildCommandPermissions for a all api.Command(s) -func (r RestClientImpl) SetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandsPermissions ...*api.SetGuildCommandPermissions) (cmdsPerms []*api.GuildCommandPermissions, err error) { - compiledRoute, err := endpoints.SetGuildCommandsPermissions.Compile(applicationID, guildID) +func (r *RestClientImpl) SetGuildCommandsPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandsPermissions ...*api.SetGuildCommandPermissions) (cmdsPerms []*api.GuildCommandPermissions, err error) { + compiledRoute, err := restclient.SetGuildCommandsPermissions.Compile(nil, applicationID, guildID) if err != nil { return nil, err } - err = r.Request(compiledRoute, api.SetGuildCommandsPermissions(commandsPermissions), &cmdsPerms) + err = r.Do(compiledRoute, api.SetGuildCommandsPermissions(commandsPermissions), &cmdsPerms) if err == nil { for _, cmdPerms := range cmdsPerms { cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) @@ -702,12 +606,12 @@ func (r RestClientImpl) SetGuildCommandsPermissions(applicationID api.Snowflake, } // SetGuildCommandPermissions sets the api.GuildCommandPermissions for a specific api.Command -func (r RestClientImpl) SetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, commandPermissions *api.SetGuildCommandPermissions) (cmdPerms *api.GuildCommandPermissions, err error) { - compiledRoute, err := endpoints.SetGuildCommandPermissions.Compile(applicationID, guildID, commandID) +func (r *RestClientImpl) SetGuildCommandPermissions(applicationID api.Snowflake, guildID api.Snowflake, commandID api.Snowflake, commandPermissions *api.SetGuildCommandPermissions) (cmdPerms *api.GuildCommandPermissions, err error) { + compiledRoute, err := restclient.SetGuildCommandPermissions.Compile(nil, applicationID, guildID, commandID) if err != nil { return nil, err } - err = r.Request(compiledRoute, commandPermissions, &cmdPerms) + err = r.Do(compiledRoute, commandPermissions, &cmdPerms) if err == nil { cmdPerms = r.Disgo().EntityBuilder().CreateGuildCommandPermissions(cmdPerms, api.CacheStrategyNoWs) } @@ -715,57 +619,57 @@ func (r RestClientImpl) SetGuildCommandPermissions(applicationID api.Snowflake, } // SendInteractionResponse used to send the initial response on an interaction -func (r RestClientImpl) SendInteractionResponse(interactionID api.Snowflake, interactionToken string, interactionResponse *api.InteractionResponse) error { - compiledRoute, err := endpoints.CreateInteractionResponse.Compile(interactionID, interactionToken) +func (r *RestClientImpl) SendInteractionResponse(interactionID api.Snowflake, interactionToken string, interactionResponse *api.InteractionResponse) error { + compiledRoute, err := restclient.CreateInteractionResponse.Compile(nil, interactionID, interactionToken) if err != nil { return err } - return r.Request(compiledRoute, interactionResponse, nil) + return r.Do(compiledRoute, interactionResponse, nil) } // EditInteractionResponse used to edit the initial response on an interaction -func (r RestClientImpl) EditInteractionResponse(applicationID api.Snowflake, interactionToken string, followupMessage *api.FollowupMessage) (message *api.Message, err error) { - compiledRoute, err := endpoints.EditInteractionResponse.Compile(applicationID, interactionToken) +func (r *RestClientImpl) EditInteractionResponse(applicationID api.Snowflake, interactionToken string, followupMessage *api.FollowupMessage) (message *api.Message, err error) { + compiledRoute, err := restclient.UpdateInteractionResponse.Compile(nil, applicationID, interactionToken) if err != nil { return nil, err } - return message, r.Request(compiledRoute, followupMessage, &message) + return message, r.Do(compiledRoute, followupMessage, &message) } // DeleteInteractionResponse used to delete the initial response on an interaction -func (r RestClientImpl) DeleteInteractionResponse(applicationID api.Snowflake, interactionToken string) error { - compiledRoute, err := endpoints.DeleteInteractionResponse.Compile(applicationID, interactionToken) +func (r *RestClientImpl) DeleteInteractionResponse(applicationID api.Snowflake, interactionToken string) error { + compiledRoute, err := restclient.DeleteInteractionResponse.Compile(nil, applicationID, interactionToken) if err != nil { return err } - return r.Request(compiledRoute, nil, nil) + return r.Do(compiledRoute, nil, nil) } // SendFollowupMessage used to send a followup message_events to an interaction -func (r RestClientImpl) SendFollowupMessage(applicationID api.Snowflake, interactionToken string, followupMessage *api.FollowupMessage) (message *api.Message, err error) { - compiledRoute, err := endpoints.CreateFollowupMessage.Compile(applicationID, interactionToken) +func (r *RestClientImpl) SendFollowupMessage(applicationID api.Snowflake, interactionToken string, followupMessage *api.FollowupMessage) (message *api.Message, err error) { + compiledRoute, err := restclient.CreateFollowupMessage.Compile(nil, applicationID, interactionToken) if err != nil { return nil, err } - return message, r.Request(compiledRoute, followupMessage, &message) + return message, r.Do(compiledRoute, followupMessage, &message) } // EditFollowupMessage used to edit a api.FollowupMessage from an api.Interaction -func (r RestClientImpl) EditFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake, followupMessage *api.FollowupMessage) (message *api.Message, err error) { - compiledRoute, err := endpoints.EditFollowupMessage.Compile(applicationID, interactionToken, messageID) +func (r *RestClientImpl) EditFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake, followupMessage *api.FollowupMessage) (message *api.Message, err error) { + compiledRoute, err := restclient.UpdateFollowupMessage.Compile(nil, applicationID, interactionToken, messageID) if err != nil { return nil, err } - return message, r.Request(compiledRoute, followupMessage, &message) + return message, r.Do(compiledRoute, followupMessage, &message) } // DeleteFollowupMessage used to delete a api.FollowupMessage from an api.Interaction -func (r RestClientImpl) DeleteFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake) error { - compiledRoute, err := endpoints.DeleteFollowupMessage.Compile(applicationID, interactionToken, messageID) +func (r *RestClientImpl) DeleteFollowupMessage(applicationID api.Snowflake, interactionToken string, messageID api.Snowflake) error { + compiledRoute, err := restclient.DeleteFollowupMessage.Compile(nil, applicationID, interactionToken, messageID) if err != nil { return err } - return r.Request(compiledRoute, nil, nil) + return r.Do(compiledRoute, nil, nil) } func normalizeEmoji(emoji string) string { From 5fc8826b33937125ac8090ab600ff45f6e0abaa8 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 28 May 2021 03:25:31 +0200 Subject: [PATCH 19/22] update rest client --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 80409f86..3820e206 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/DisgoOrg/log v1.0.3 - github.com/DisgoOrg/restclient v1.1.3 + github.com/DisgoOrg/restclient v1.1.4 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 github.com/stretchr/testify v1.7.0 From 6beb10a15b333d49b63ac2d3e5aeaa9e0f66d654 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 28 May 2021 03:27:24 +0200 Subject: [PATCH 20/22] fixed go.sum --- go.sum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 32ffdfd5..6bb9bf7b 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/DisgoOrg/log v1.0.3 h1:IjmZQQu/kuBIui22EdXmxzQGYwcPCJEkXa0Fe6W9fJk= github.com/DisgoOrg/log v1.0.3/go.mod h1:KFGKhBQr37d6rxZ7p2bmc8BEmDH8DZbtgdlJDSCsE7I= -github.com/DisgoOrg/restclient v1.1.3 h1:ZspV/tSwzCSffIZMRctS+ryzKmgNrKEqKMH6UQW819A= -github.com/DisgoOrg/restclient v1.1.3/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= +github.com/DisgoOrg/restclient v1.1.4 h1:mjl6bRfq8Lj2n0zpMV4hcozVF1AQioG1huiJSs5ZSjY= +github.com/DisgoOrg/restclient v1.1.4/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= From dcae5115af74c89a9937c1f7efdeedf5aacd6c0d Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 28 May 2021 10:49:51 +0200 Subject: [PATCH 21/22] added comment --- internal/restclient_impl.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/restclient_impl.go b/internal/restclient_impl.go index 8090960e..17ada390 100644 --- a/internal/restclient_impl.go +++ b/internal/restclient_impl.go @@ -34,6 +34,7 @@ func (r *RestClientImpl) Close() { r.HttpClient().CloseIdleConnections() } +// DoWithHeaders executes a rest request with custom headers func (r *RestClientImpl) DoWithHeaders(route *restclient.CompiledAPIRoute, rqBody interface{}, rsBody interface{}, customHeader http.Header) (err restclient.RestError) { err = r.RestClient.DoWithHeaders(route, rqBody, rsBody, customHeader) // TODO reimplement events.HTTPRequestEvent From ad67e2d8fb0db7161329ebe05858f5ed4545ada8 Mon Sep 17 00:00:00 2001 From: TopiSenpai Date: Fri, 28 May 2021 18:46:02 +0200 Subject: [PATCH 22/22] moved some stuff from Generic/Command/ButtonInteractionEvent to Interaction/ButtonInteraction/CommandInteraction --- api/entity_builder.go | 4 +- api/events/interaction_events.go | 53 ++++------- api/interaction.go | 89 ++++++++++++++----- example/go.sum | 2 + internal/entity_builder_impl.go | 26 +++--- .../handlers/interaction_create_handler.go | 11 +-- 6 files changed, 108 insertions(+), 77 deletions(-) diff --git a/api/entity_builder.go b/api/entity_builder.go index 22c5dc6a..41c179a2 100644 --- a/api/entity_builder.go +++ b/api/entity_builder.go @@ -15,8 +15,8 @@ var ( type EntityBuilder interface { Disgo() Disgo - CreateButtonInteraction(fullInteraction *FullInteraction, updateCache CacheStrategy) *ButtonInteraction - CreateCommandInteraction(fullInteraction *FullInteraction, updateCache CacheStrategy) *CommandInteraction + CreateButtonInteraction(fullInteraction *FullInteraction, c chan *InteractionResponse, updateCache CacheStrategy) *ButtonInteraction + CreateCommandInteraction(fullInteraction *FullInteraction, c chan *InteractionResponse, updateCache CacheStrategy) *CommandInteraction CreateGlobalCommand(command *Command, updateCache CacheStrategy) *Command diff --git a/api/events/interaction_events.go b/api/events/interaction_events.go index 1d175b23..1e18049f 100644 --- a/api/events/interaction_events.go +++ b/api/events/interaction_events.go @@ -1,83 +1,64 @@ package events import ( - "errors" - "github.com/DisgoOrg/disgo/api" ) // GenericInteractionEvent generic api.Interaction event type GenericInteractionEvent struct { GenericEvent - Interaction *api.Interaction - ResponseChannel chan *api.InteractionResponse - FromWebhook bool - Replied bool + Interaction *api.Interaction } // Reply replies to the api.Interaction with the provided api.InteractionResponse func (e *GenericInteractionEvent) Reply(response *api.InteractionResponse) error { - if e.Replied { - return errors.New("you already replied to this interaction") - } - e.Replied = true - - if e.FromWebhook { - e.ResponseChannel <- response - return nil - } - - return e.Disgo().RestClient().SendInteractionResponse(e.Interaction.ID, e.Interaction.Token, response) + return e.Interaction.Reply(response) } // EditOriginal edits the original api.InteractionResponse func (e *GenericInteractionEvent) EditOriginal(followupMessage *api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().EditInteractionResponse(e.Disgo().ApplicationID(), e.Interaction.Token, followupMessage) + return e.Interaction.EditOriginal(followupMessage) } // DeleteOriginal deletes the original api.InteractionResponse func (e *GenericInteractionEvent) DeleteOriginal() error { - return e.Disgo().RestClient().DeleteInteractionResponse(e.Disgo().ApplicationID(), e.Interaction.Token) + return e.Interaction.DeleteOriginal() } // SendFollowup used to send a api.FollowupMessage to an api.Interaction func (e *GenericInteractionEvent) SendFollowup(followupMessage *api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().SendFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, followupMessage) + return e.Interaction.SendFollowup(followupMessage) } // EditFollowup used to edit a api.FollowupMessage from an api.Interaction func (e *GenericInteractionEvent) EditFollowup(messageID api.Snowflake, followupMessage *api.FollowupMessage) (*api.Message, error) { - return e.Disgo().RestClient().EditFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID, followupMessage) + return e.Interaction.EditFollowup(messageID, followupMessage) } // DeleteFollowup used to delete a api.FollowupMessage from an api.Interaction func (e *GenericInteractionEvent) DeleteFollowup(messageID api.Snowflake) error { - return e.Disgo().RestClient().DeleteFollowupMessage(e.Disgo().ApplicationID(), e.Interaction.Token, messageID) + return e.Interaction.DeleteFollowup(messageID) } // CommandEvent indicates that a slash api.Command was ran type CommandEvent struct { GenericInteractionEvent - CommandInteraction *api.CommandInteraction - CommandID api.Snowflake - CommandName string - SubCommandName *string - SubCommandGroupName *string - Options []*api.Option + CommandInteraction *api.CommandInteraction + CommandID api.Snowflake + CommandName string + SubCommandName *string + SubCommandGroupName *string + Options []*api.Option } // DeferReply replies to the api.CommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource and shows a loading state func (e *CommandEvent) DeferReply(ephemeral bool) error { - var data *api.InteractionResponseData - if ephemeral { - data = &api.InteractionResponseData{Flags: api.MessageFlagEphemeral} - } - return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredChannelMessageWithSource, Data: data}) + return e.CommandInteraction.DeferReply(ephemeral) } // ReplyCreate replies to the api.CommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource & api.InteractionResponseData func (e *CommandEvent) ReplyCreate(data *api.InteractionResponseData) error { - return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeChannelMessageWithSource, Data: data}) + return e.CommandInteraction.ReplyCreate(data) } // CommandPath returns the api.Command path @@ -131,12 +112,12 @@ type ButtonClickEvent struct { // DeferEdit replies to the api.ButtonInteraction with api.InteractionResponseTypeDeferredUpdateMessage and cancels the loading state func (e *ButtonClickEvent) DeferEdit() error { - return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeDeferredUpdateMessage}) + return e.ButtonInteraction.DeferEdit() } // ReplyEdit replies to the api.ButtonInteraction with api.InteractionResponseTypeUpdateMessage & api.InteractionResponseData which edits the original api.Message func (e *ButtonClickEvent) ReplyEdit(data *api.InteractionResponseData) error { - return e.Reply(&api.InteractionResponse{Type: api.InteractionResponseTypeUpdateMessage, Data: data}) + return e.ButtonInteraction.ReplyEdit(data) } // CustomID returns the customID from the called api.Button diff --git a/api/interaction.go b/api/interaction.go index fad71554..ca5b4222 100644 --- a/api/interaction.go +++ b/api/interaction.go @@ -1,6 +1,9 @@ package api -import "encoding/json" +import ( + "encoding/json" + "errors" +) // InteractionType is the type of Interaction type InteractionType int @@ -12,6 +15,41 @@ const ( InteractionTypeComponent ) +// Interaction holds the general parameters of each Interaction +type Interaction struct { + Disgo Disgo + ResponseChannel chan *InteractionResponse + Replied bool + ID Snowflake `json:"id"` + Type InteractionType `json:"type"` + GuildID *Snowflake `json:"guild_id,omitempty"` + ChannelID *Snowflake `json:"channel_id,omitempty"` + Member *Member `json:"member,omitempty"` + User *User `json:"User,omitempty"` + Token string `json:"token"` + Version int `json:"version"` +} + +// Reply replies to the api.Interaction with the provided api.InteractionResponse +func (i *Interaction) Reply(response *InteractionResponse) error { + if i.Replied { + return errors.New("you already replied to this interaction") + } + i.Replied = true + + if i.FromWebhook() { + i.ResponseChannel <- response + return nil + } + + return i.Disgo.RestClient().SendInteractionResponse(i.ID, i.Token, response) +} + +// FromWebhook returns is the Interaction was made via http +func (i *Interaction) FromWebhook() bool { + return i.ResponseChannel != nil +} + // Guild returns the api.Guild from the api.Cache func (i *Interaction) Guild() *Guild { if i.GuildID == nil { @@ -91,17 +129,24 @@ type FullInteraction struct { Data json.RawMessage `json:"data,omitempty"` } -// Interaction holds the general parameters of each Interaction -type Interaction struct { - Disgo Disgo - ID Snowflake `json:"id"` - Type InteractionType `json:"type"` - GuildID *Snowflake `json:"guild_id,omitempty"` - ChannelID *Snowflake `json:"channel_id,omitempty"` - Member *Member `json:"member,omitempty"` - User *User `json:"User,omitempty"` - Token string `json:"token"` - Version int `json:"version"` +// CommandInteraction is a specific Interaction when using Command(s) +type CommandInteraction struct { + *Interaction + Data *CommandInteractionData `json:"data,omitempty"` +} + +// DeferReply replies to the api.CommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource and shows a loading state +func (i *CommandInteraction) DeferReply(ephemeral bool) error { + var data *InteractionResponseData + if ephemeral { + data = &InteractionResponseData{Flags: MessageFlagEphemeral} + } + return i.Reply(&InteractionResponse{Type: InteractionResponseTypeDeferredChannelMessageWithSource, Data: data}) +} + +// ReplyCreate replies to the api.CommandInteraction with api.InteractionResponseTypeDeferredChannelMessageWithSource & api.InteractionResponseData +func (i *CommandInteraction) ReplyCreate(data *InteractionResponseData) error { + return i.Reply(&InteractionResponse{Type: InteractionResponseTypeChannelMessageWithSource, Data: data}) } // ButtonInteraction is a specific Interaction when CLicked on Button(s) @@ -111,16 +156,14 @@ type ButtonInteraction struct { Data *ButtonInteractionData `json:"data,omitempty"` } -// CommandInteraction is a specific Interaction when using Command(s) -type CommandInteraction struct { - *Interaction - Data *CommandInteractionData `json:"data,omitempty"` +// DeferEdit replies to the api.ButtonInteraction with api.InteractionResponseTypeDeferredUpdateMessage and cancels the loading state +func (i *ButtonInteraction) DeferEdit() error { + return i.Reply(&InteractionResponse{Type: InteractionResponseTypeDeferredUpdateMessage}) } -// ButtonInteractionData is the command data payload -type ButtonInteractionData struct { - CustomID string `json:"custom_id"` - ComponentType ComponentType `json:"component_type"` +// ReplyEdit replies to the api.ButtonInteraction with api.InteractionResponseTypeUpdateMessage & api.InteractionResponseData which edits the original api.Message +func (i *ButtonInteraction) ReplyEdit(data *InteractionResponseData) error { + return i.Reply(&InteractionResponse{Type: InteractionResponseTypeUpdateMessage, Data: data}) } // CommandInteractionData is the command data payload @@ -131,6 +174,12 @@ type CommandInteractionData struct { Options []*OptionData `json:"options,omitempty"` } +// ButtonInteractionData is the command data payload +type ButtonInteractionData struct { + CustomID string `json:"custom_id"` + ComponentType ComponentType `json:"component_type"` +} + // Resolved contains resolved mention data type Resolved struct { Users map[Snowflake]*User `json:"users,omitempty"` diff --git a/example/go.sum b/example/go.sum index d27607c8..c7226593 100644 --- a/example/go.sum +++ b/example/go.sum @@ -6,6 +6,8 @@ github.com/DisgoOrg/restclient v1.1.2 h1:KxpWL3t587EFjfwELVsWVrEeoBIQCcKXCTEBffC github.com/DisgoOrg/restclient v1.1.2/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= github.com/DisgoOrg/restclient v1.1.3 h1:ZspV/tSwzCSffIZMRctS+ryzKmgNrKEqKMH6UQW819A= github.com/DisgoOrg/restclient v1.1.3/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= +github.com/DisgoOrg/restclient v1.1.4 h1:mjl6bRfq8Lj2n0zpMV4hcozVF1AQioG1huiJSs5ZSjY= +github.com/DisgoOrg/restclient v1.1.4/go.mod h1:PIhyYsT52w5T6m4LT+HTdKqY6NOIqo71Ai0rgaq9ZtM= github.com/PaesslerAG/gval v1.1.0 h1:k3RuxeZDO3eejD4cMPSt+74tUSvTnbGvLx0df4mdwFc= github.com/PaesslerAG/gval v1.1.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= diff --git a/internal/entity_builder_impl.go b/internal/entity_builder_impl.go index fafb3bb7..3ad9c0bb 100644 --- a/internal/entity_builder_impl.go +++ b/internal/entity_builder_impl.go @@ -20,15 +20,17 @@ func (b *EntityBuilderImpl) Disgo() api.Disgo { return b.disgo } -func (b EntityBuilderImpl) createInteraction(fullInteraction *api.FullInteraction, updateCache api.CacheStrategy) *api.Interaction { +func (b EntityBuilderImpl) createInteraction(fullInteraction *api.FullInteraction, c chan *api.InteractionResponse, updateCache api.CacheStrategy) *api.Interaction { interaction := &api.Interaction{ - Disgo: b.disgo, - ID: fullInteraction.ID, - Type: fullInteraction.Type, - GuildID: fullInteraction.GuildID, - ChannelID: fullInteraction.ChannelID, - Token: fullInteraction.Token, - Version: fullInteraction.Version, + Disgo: b.disgo, + ResponseChannel: c, + Replied: false, + ID: fullInteraction.ID, + Type: fullInteraction.Type, + GuildID: fullInteraction.GuildID, + ChannelID: fullInteraction.ChannelID, + Token: fullInteraction.Token, + Version: fullInteraction.Version, } if fullInteraction.Member != nil { @@ -41,19 +43,19 @@ func (b EntityBuilderImpl) createInteraction(fullInteraction *api.FullInteractio } // CreateButtonInteraction creates a api.ButtonInteraction from the full interaction response -func (b *EntityBuilderImpl) CreateButtonInteraction(fullInteraction *api.FullInteraction, updateCache api.CacheStrategy) *api.ButtonInteraction { +func (b *EntityBuilderImpl) CreateButtonInteraction(fullInteraction *api.FullInteraction, c chan *api.InteractionResponse, updateCache api.CacheStrategy) *api.ButtonInteraction { var data *api.ButtonInteractionData _ = json.Unmarshal(fullInteraction.Data, &data) return &api.ButtonInteraction{ - Interaction: b.createInteraction(fullInteraction, updateCache), + Interaction: b.createInteraction(fullInteraction, c, updateCache), Message: b.CreateMessage(fullInteraction.FullMessage, updateCache), Data: data, } } // CreateCommandInteraction creates a api.CommandInteraction from the full interaction response -func (b *EntityBuilderImpl) CreateCommandInteraction(fullInteraction *api.FullInteraction, updateCache api.CacheStrategy) *api.CommandInteraction { +func (b *EntityBuilderImpl) CreateCommandInteraction(fullInteraction *api.FullInteraction, c chan *api.InteractionResponse, updateCache api.CacheStrategy) *api.CommandInteraction { var data *api.CommandInteractionData _ = json.Unmarshal(fullInteraction.Data, &data) @@ -85,7 +87,7 @@ func (b *EntityBuilderImpl) CreateCommandInteraction(fullInteraction *api.FullIn } return &api.CommandInteraction{ - Interaction: b.createInteraction(fullInteraction, updateCache), + Interaction: b.createInteraction(fullInteraction, c, updateCache), Data: data, } } diff --git a/internal/handlers/interaction_create_handler.go b/internal/handlers/interaction_create_handler.go index 4bb2fff4..61c82373 100644 --- a/internal/handlers/interaction_create_handler.go +++ b/internal/handlers/interaction_create_handler.go @@ -29,15 +29,12 @@ func (h InteractionCreateHandler) HandleGatewayEvent(disgo api.Disgo, eventManag func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceNumber int, fullInteraction *api.FullInteraction, c chan *api.InteractionResponse) { genericInteractionEvent := events.GenericInteractionEvent{ - GenericEvent: events.NewEvent(disgo, sequenceNumber), - ResponseChannel: c, - FromWebhook: c != nil, - Replied: false, + GenericEvent: events.NewEvent(disgo, sequenceNumber), } switch fullInteraction.Type { case api.InteractionTypeCommand: - interaction := disgo.EntityBuilder().CreateCommandInteraction(fullInteraction, api.CacheStrategyYes) + interaction := disgo.EntityBuilder().CreateCommandInteraction(fullInteraction, c, api.CacheStrategyYes) genericInteractionEvent.Interaction = interaction.Interaction eventManager.Dispatch(genericInteractionEvent) @@ -70,7 +67,7 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN eventManager.Dispatch(events.CommandEvent{ GenericInteractionEvent: genericInteractionEvent, - CommandInteraction: interaction, + CommandInteraction: interaction, CommandID: interaction.Data.ID, CommandName: interaction.Data.Name, SubCommandName: subCommandName, @@ -78,7 +75,7 @@ func handleInteraction(disgo api.Disgo, eventManager api.EventManager, sequenceN Options: newOptions, }) case api.InteractionTypeComponent: - interaction := disgo.EntityBuilder().CreateButtonInteraction(fullInteraction, api.CacheStrategyYes) + interaction := disgo.EntityBuilder().CreateButtonInteraction(fullInteraction, c, api.CacheStrategyYes) genericInteractionEvent.Interaction = interaction.Interaction eventManager.Dispatch(genericInteractionEvent)