From 75c1ea3eb5f9cc89dc1e6617d63aae3775ac8c53 Mon Sep 17 00:00:00 2001 From: biast12 Date: Sun, 1 Mar 2026 23:31:57 +0100 Subject: [PATCH 01/73] Expand MessageType enum with new values Reorganize MessageType constants and add many new message type values using iota offsets. Notable additions: ContextMenuCommand, AutoModerationAction, RoleSubscriptionPurchase, InteractionPremiumUpsell, StageStart/End/Speaker/Topic, GuildApplicationPremiumSubscription, Guild incident alert/report types, PurchaseNotification, and PollResult. GuildDiscoveryDisqualified was moved and numeric offsets adjusted to preserve intended values. --- objects/channel/message/messagetype.go | 32 +++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/objects/channel/message/messagetype.go b/objects/channel/message/messagetype.go index 6de99ba..363d438 100644 --- a/objects/channel/message/messagetype.go +++ b/objects/channel/message/messagetype.go @@ -16,7 +16,10 @@ const ( MessageTypeUserPremiumGuildSubscriptionTier2 MessageTypeUserPremiumGuildSubscriptionTier3 MessageTypeChannelFollowAdd - MessageTypeGuildDiscoveryDisqualified +) + +const ( + MessageTypeGuildDiscoveryDisqualified MessageType = iota + 14 MessageTypeGuildDiscoveryRequalified MessageTypeGuildDiscoveryGracePeriodInitialWarning MessageTypeGuildDiscoveryGracePeriodFinalWarning @@ -25,4 +28,31 @@ const ( MessageTypeApplicationCommand MessageTypeThreadStarterMessage MessageTypeGuildInviteReminder + MessageTypeContextMenuCommand + MessageTypeAutoModerationAction + MessageTypeRoleSubscriptionPurchase + MessageTypeInteractionPremiumUpsell + MessageTypeStageStart + MessageTypeStageEnd + MessageTypeStageSpeaker +) + +const ( + MessageTypeStageTopic MessageType = iota + 31 + MessageTypeGuildApplicationPremiumSubscription +) + +const ( + MessageTypeGuildIncidentAlertModeEnabled MessageType = iota + 36 + MessageTypeGuildIncidentAlertModeDisabled + MessageTypeGuildIncidentReportRaid + MessageTypeGuildIncidentReportFalseAlarm +) + +const ( + MessageTypePurchaseNotification MessageType = iota + 44 +) + +const ( + MessageTypePollResult MessageType = iota + 46 ) From fc2b4d33cbcdfd11b8516ed67a77f6c55e52ad48 Mon Sep 17 00:00:00 2001 From: biast12 Date: Sun, 1 Mar 2026 23:32:44 +0100 Subject: [PATCH 02/73] Fix typo and add new message flags Rename FlagSupressEmbeds to FlagSuppressEmbeds and replace an unused placeholder with FlagHasThread. Add additional message flags (FlagFailedToMentionSomeRolesInThread) and introduce a new const block for higher-bit flags: FlagSuppressNotifications, FlagIsVoiceMessage, FlagHasSnapshot, and FlagIsComponentsV2, reorganizing flag definitions for clarity. --- objects/channel/message/messageflags.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/objects/channel/message/messageflags.go b/objects/channel/message/messageflags.go index dc5601f..1c47749 100644 --- a/objects/channel/message/messageflags.go +++ b/objects/channel/message/messageflags.go @@ -5,13 +5,20 @@ type MessageFlag uint const ( FlagCrossposted MessageFlag = 1 << iota FlagIsCrosspost - FlagSupressEmbeds + FlagSuppressEmbeds FlagSourceMessageDeleted FlagUrgent - _ // 1 << 5 not documented + FlagHasThread FlagEphemeral FlagLoading - FlagComponentsV2 MessageFlag = 1 << 15 + FlagFailedToMentionSomeRolesInThread +) + +const ( + FlagSuppressNotifications MessageFlag = 1 << (iota + 12) + FlagIsVoiceMessage + FlagHasSnapshot + FlagIsComponentsV2 ) func SumFlags(flags ...MessageFlag) (sum uint) { From 33b48e7d937744b3b6dd04aa317a8e368bcd23d5 Mon Sep 17 00:00:00 2001 From: biast12 Date: Sun, 1 Mar 2026 23:32:57 +0100 Subject: [PATCH 03/73] Add label/file-upload and reorder component constants Insert new component types (ComponentLabel, ComponentFileUpload) and reorganize the constant blocks to adjust enum offsets. ComponentContainer is moved to start at iota+17 and ComponentRadioGroup at iota+21, shifting subsequent values so the numeric IDs align with the newly added components. --- objects/interaction/component/component.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/objects/interaction/component/component.go b/objects/interaction/component/component.go index f2523a8..f0fe555 100644 --- a/objects/interaction/component/component.go +++ b/objects/interaction/component/component.go @@ -23,10 +23,16 @@ const ( ComponentMediaGallery ComponentFile ComponentSeparator - ComponentContainer ComponentType = iota + 3 // 14 +) + +const ( + ComponentContainer ComponentType = iota + 17 ComponentLabel ComponentFileUpload - ComponentRadioGroup ComponentType = iota + 4 // 21 +) + +const ( + ComponentRadioGroup ComponentType = iota + 21 ComponentCheckboxGroup ComponentCheckbox ) From 694273a7912801eb48acd7d3f82354942aad81c9 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 20:01:35 +0100 Subject: [PATCH 04/73] Add new gateway events and update models Introduce many new gateway event payloads and expand existing ones to support additional Discord events/fields (auto-moderation, scheduled events, soundboard, stickers, integrations, stage instances, subscriptions, message poll votes, voice channel effects, thread updates, application command permissions, etc.). Update EventType and EventTypes mapping to include new event constants and types. Adjust event structs to use pointer types for optional fields (e.g. guild_id, timestamps, endpoints) and add new fields where required. Fix cache voice state handling: handle nil GuildId when storing voice states (Bolt and Memory caches), use member.User pointer semantics to avoid nil-pointer issues, and update CachedVoiceState.ToVoiceState to return pointer-backed VoiceState values. Also update restwrapper to dereference member user when collecting users. Modify core guild and role models (rename voice_states field, add role icon/unicode emoji/flags and role tags ordering) and add new object types for automoderation and scheduled events. These changes enable support for newer gateway payloads and improve robustness around optional/nullable fields and voice state caching. --- cache/boltcache.go | 10 +- cache/memorycache.go | 24 ++- gateway/cachelisteners.go | 2 +- .../applicationcommandpermissionsupdate.go | 7 + gateway/payloads/events/automoderation.go | 29 ++++ gateway/payloads/events/channelpinsupdate.go | 10 +- gateway/payloads/events/eventtype.go | 126 +++++++++----- gateway/payloads/events/eventtypes.go | 164 +++++++++++++----- .../events/guildauditlogentrycreate.go | 8 + gateway/payloads/events/guildmemberschunk.go | 11 +- gateway/payloads/events/guildmemberupdate.go | 17 +- gateway/payloads/events/guildrolecreate.go | 2 +- gateway/payloads/events/guildroleupdate.go | 2 +- .../payloads/events/guildscheduledevents.go | 27 +++ gateway/payloads/events/guildsoundboard.go | 26 +++ .../payloads/events/guildstickersupdate.go | 8 + gateway/payloads/events/integrations.go | 19 ++ gateway/payloads/events/invitecreate.go | 26 ++- gateway/payloads/events/invitedelete.go | 6 +- gateway/payloads/events/messagedelete.go | 6 +- gateway/payloads/events/messagedeletebulk.go | 4 +- gateway/payloads/events/messagepollvote.go | 17 ++ gateway/payloads/events/messagereactionadd.go | 16 +- .../payloads/events/messagereactionremove.go | 10 +- .../events/messagereactionremoveemoji.go | 8 +- gateway/payloads/events/ready.go | 18 +- gateway/payloads/events/stageinstances.go | 15 ++ gateway/payloads/events/subscriptions.go | 15 ++ gateway/payloads/events/threadcreate.go | 5 +- gateway/payloads/events/threaddelete.go | 9 +- .../payloads/events/threadmembersupdate.go | 2 +- gateway/payloads/events/threadmemberupdate.go | 5 +- .../payloads/events/voicechanneleffectsend.go | 14 ++ gateway/payloads/events/voiceserverupdate.go | 2 +- gateway/restwrapper.go | 4 +- objects/automoderation/automoderation.go | 61 +++++++ objects/guild/cachedvoicestate.go | 18 +- objects/guild/guild.go | 2 +- objects/guild/role.go | 25 +-- .../guild/scheduledevent/scheduledevent.go | 53 ++++++ objects/guild/sticker/sticker.go | 33 ++++ objects/guild/voicestate.go | 36 ++-- .../applicationcommandpermissions.go | 10 +- objects/member/cachedmember.go | 10 +- objects/member/member.go | 28 ++- objects/soundboard/soundboard.go | 14 ++ objects/stage/stage.go | 11 ++ objects/subscription/subscription.go | 28 +++ 48 files changed, 785 insertions(+), 218 deletions(-) create mode 100644 gateway/payloads/events/applicationcommandpermissionsupdate.go create mode 100644 gateway/payloads/events/automoderation.go create mode 100644 gateway/payloads/events/guildauditlogentrycreate.go create mode 100644 gateway/payloads/events/guildscheduledevents.go create mode 100644 gateway/payloads/events/guildsoundboard.go create mode 100644 gateway/payloads/events/guildstickersupdate.go create mode 100644 gateway/payloads/events/integrations.go create mode 100644 gateway/payloads/events/messagepollvote.go create mode 100644 gateway/payloads/events/stageinstances.go create mode 100644 gateway/payloads/events/subscriptions.go create mode 100644 gateway/payloads/events/voicechanneleffectsend.go create mode 100644 objects/automoderation/automoderation.go create mode 100644 objects/guild/scheduledevent/scheduledevent.go create mode 100644 objects/guild/sticker/sticker.go create mode 100644 objects/soundboard/soundboard.go create mode 100644 objects/stage/stage.go create mode 100644 objects/subscription/subscription.go diff --git a/cache/boltcache.go b/cache/boltcache.go index cc3d242..387dcc7 100644 --- a/cache/boltcache.go +++ b/cache/boltcache.go @@ -732,7 +732,11 @@ func (c *BoltCache) StoreVoiceStates(states []guild.VoiceState) { for _, state := range states { if encoded, err := json.Marshal(state.ToCachedVoiceState()); err == nil { - if err := b.Put(memberToBytes(state.UserId, state.GuildId), encoded); err != nil { + guildId := uint64(0) + if state.GuildId != nil { + guildId = *state.GuildId + } + if err := b.Put(memberToBytes(state.UserId, guildId), encoded); err != nil { return err } } else { @@ -766,7 +770,7 @@ func (c *BoltCache) GetVoiceState(userId, guildId uint64) (guild.VoiceState, boo u = user.User{Id: userId} } - m = member.Member{User: u} + m = member.Member{User: &u} } state := cached.ToVoiceState(guildId, m) @@ -805,7 +809,7 @@ func (c *BoltCache) GetGuildVoiceStates(guildId uint64) []guild.VoiceState { u = user.User{Id: stateUserId} } - m = member.Member{User: u} + m = member.Member{User: &u} } states = append(states, cached.ToVoiceState(guildId, m)) diff --git a/cache/memorycache.go b/cache/memorycache.go index 0bf1cf2..b75228d 100644 --- a/cache/memorycache.go +++ b/cache/memorycache.go @@ -677,11 +677,15 @@ func (c *MemoryCache) StoreVoiceStates(ctx context.Context, states []guild.Voice defer c.voiceStateLock.Unlock() for _, state := range states { - if c.voiceStates[state.GuildId] == nil { - c.voiceStates[state.GuildId] = make(map[uint64]guild.CachedVoiceState) + if state.GuildId == nil { + continue + } + guildId := *state.GuildId + if c.voiceStates[guildId] == nil { + c.voiceStates[guildId] = make(map[uint64]guild.CachedVoiceState) } - c.voiceStates[state.GuildId][state.UserId] = state.ToCachedVoiceState() + c.voiceStates[guildId][state.UserId] = state.ToCachedVoiceState() } } @@ -702,11 +706,8 @@ func (c *MemoryCache) GetVoiceState(ctx context.Context, userId, guildId uint64) // get member m, err := c.GetMember(ctx, guildId, userId) if err == ErrNotFound { - m = member.Member{ - User: user.User{ - Id: userId, - }, - } + u := user.User{Id: userId} + m = member.Member{User: &u} } else if err != nil { return guild.VoiceState{}, err } @@ -730,11 +731,8 @@ func (c *MemoryCache) GetGuildVoiceStates(ctx context.Context, guildId uint64) ( // get member m, err := c.GetMember(ctx, guildId, userId) if err == ErrNotFound { - m = member.Member{ - User: user.User{ - Id: userId, - }, - } + u := user.User{Id: userId} + m = member.Member{User: &u} } else if err != nil { return nil, err } diff --git a/gateway/cachelisteners.go b/gateway/cachelisteners.go index 90eef89..b80acb5 100644 --- a/gateway/cachelisteners.go +++ b/gateway/cachelisteners.go @@ -78,7 +78,7 @@ func guildMemberRemoveListener(s *Shard, e *events.GuildMemberRemove) { func guildMemberUpdateListener(s *Shard, e *events.GuildMemberUpdate) { s.Cache.StoreMember(context.Background(), member.Member{ - User: e.User, + User: &e.User, Nick: e.Nick, Roles: e.Roles, PremiumSince: e.PremiumSince, diff --git a/gateway/payloads/events/applicationcommandpermissionsupdate.go b/gateway/payloads/events/applicationcommandpermissionsupdate.go new file mode 100644 index 0000000..c2b6e03 --- /dev/null +++ b/gateway/payloads/events/applicationcommandpermissionsupdate.go @@ -0,0 +1,7 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/interaction" + +type ApplicationCommandPermissionsUpdate struct { + interaction.GuildApplicationCommandPermissions +} diff --git a/gateway/payloads/events/automoderation.go b/gateway/payloads/events/automoderation.go new file mode 100644 index 0000000..dd7db07 --- /dev/null +++ b/gateway/payloads/events/automoderation.go @@ -0,0 +1,29 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/automoderation" + +type AutoModerationRuleCreate struct { + automoderation.Rule +} + +type AutoModerationRuleUpdate struct { + automoderation.Rule +} + +type AutoModerationRuleDelete struct { + automoderation.Rule +} + +type AutoModerationActionExecution struct { + GuildId uint64 `json:"guild_id,string"` + Action automoderation.Action `json:"action"` + RuleId uint64 `json:"rule_id,string"` + RuleTriggerType automoderation.TriggerType `json:"rule_trigger_type"` + UserId uint64 `json:"user_id,string"` + ChannelId *uint64 `json:"channel_id,string"` + MessageId *uint64 `json:"message_id,string"` + AlertSystemMessageId *uint64 `json:"alert_system_message_id,string"` + Content *string `json:"content"` + MatchedKeyword *string `json:"matched_keyword"` + MatchedContent *string `json:"matched_content"` +} diff --git a/gateway/payloads/events/channelpinsupdate.go b/gateway/payloads/events/channelpinsupdate.go index b81be14..afc31e8 100644 --- a/gateway/payloads/events/channelpinsupdate.go +++ b/gateway/payloads/events/channelpinsupdate.go @@ -1,11 +1,9 @@ package events -import ( - "time" -) +import "time" type ChannelPinsUpdate struct { - GuildId uint64 `json:"guild_id,string"` - ChannelId uint64 `json:"channel_id,string"` - LastPinTimestamp time.Time `json:"last_pin_timestamp"` + GuildId *uint64 `json:"guild_id,string"` + ChannelId uint64 `json:"channel_id,string"` + LastPinTimestamp *time.Time `json:"last_pin_timestamp"` } diff --git a/gateway/payloads/events/eventtype.go b/gateway/payloads/events/eventtype.go index 9b580a8..7a40be7 100644 --- a/gateway/payloads/events/eventtype.go +++ b/gateway/payloads/events/eventtype.go @@ -3,33 +3,71 @@ package events type EventType string const ( - READY EventType = "READY" - RESUMED EventType = "RESUMED" - RECONNECT EventType = "RECONNECT" - INVALID_SESSION EventType = "INVALID_SESSION" - CHANNEL_CREATE EventType = "CHANNEL_CREATE" - CHANNEL_UPDATE EventType = "CHANNEL_UPDATE" - CHANNEL_DELETE EventType = "CHANNEL_DELETE" - CHANNEL_PINS_UPDATE EventType = "CHANNEL_PINS_UPDATE" - ENTITLEMENT_CREATE EventType = "ENTITLEMENT_CREATE" - ENTITLEMENT_UPDATE EventType = "ENTITLEMENT_UPDATE" - ENTITLEMENT_DELETE EventType = "ENTITLEMENT_DELETE" - GUILD_CREATE EventType = "GUILD_CREATE" - GUILD_UPDATE EventType = "GUILD_UPDATE" - GUILD_DELETE EventType = "GUILD_DELETE" - GUILD_BAN_ADD EventType = "GUILD_BAN_ADD" - GUILD_BAN_REMOVE EventType = "GUILD_BAN_REMOVE" - GUILD_EMOJIS_UPDATE EventType = "GUILD_EMOJIS_UPDATE" - GUILD_INTEGRATIONS_UPDATE EventType = "GUILD_INTEGRATIONS_UPDATE" - GUILD_MEMBER_ADD EventType = "GUILD_MEMBER_ADD" - GUILD_MEMBER_REMOVE EventType = "GUILD_MEMBER_REMOVE" - GUILD_MEMBER_UPDATE EventType = "GUILD_MEMBER_UPDATE" - GUILD_MEMBERS_CHUNK EventType = "GUILD_MEMBERS_CHUNK" - GUILD_ROLE_CREATE EventType = "GUILD_ROLE_CREATE" - GUILD_ROLE_UPDATE EventType = "GUILD_ROLE_UPDATE" - GUILD_ROLE_DELETE EventType = "GUILD_ROLE_DELETE" - INVITE_CREATE EventType = "INVITE_CREATE" - INVITE_DELETE EventType = "INVITE_DELETE" + READY EventType = "READY" + RESUMED EventType = "RESUMED" + RECONNECT EventType = "RECONNECT" + INVALID_SESSION EventType = "INVALID_SESSION" + + APPLICATION_COMMAND_PERMISSIONS_UPDATE EventType = "APPLICATION_COMMAND_PERMISSIONS_UPDATE" + + AUTO_MODERATION_RULE_CREATE EventType = "AUTO_MODERATION_RULE_CREATE" + AUTO_MODERATION_RULE_UPDATE EventType = "AUTO_MODERATION_RULE_UPDATE" + AUTO_MODERATION_RULE_DELETE EventType = "AUTO_MODERATION_RULE_DELETE" + AUTO_MODERATION_ACTION_EXECUTION EventType = "AUTO_MODERATION_ACTION_EXECUTION" + + CHANNEL_CREATE EventType = "CHANNEL_CREATE" + CHANNEL_UPDATE EventType = "CHANNEL_UPDATE" + CHANNEL_DELETE EventType = "CHANNEL_DELETE" + CHANNEL_PINS_UPDATE EventType = "CHANNEL_PINS_UPDATE" + + THREAD_CREATE EventType = "THREAD_CREATE" + THREAD_UPDATE EventType = "THREAD_UPDATE" + THREAD_DELETE EventType = "THREAD_DELETE" + THREAD_LIST_SYNC EventType = "THREAD_LIST_SYNC" + THREAD_MEMBER_UPDATE EventType = "THREAD_MEMBER_UPDATE" + THREAD_MEMBERS_UPDATE EventType = "THREAD_MEMBERS_UPDATE" + + ENTITLEMENT_CREATE EventType = "ENTITLEMENT_CREATE" + ENTITLEMENT_UPDATE EventType = "ENTITLEMENT_UPDATE" + ENTITLEMENT_DELETE EventType = "ENTITLEMENT_DELETE" + + GUILD_CREATE EventType = "GUILD_CREATE" + GUILD_UPDATE EventType = "GUILD_UPDATE" + GUILD_DELETE EventType = "GUILD_DELETE" + GUILD_AUDIT_LOG_ENTRY_CREATE EventType = "GUILD_AUDIT_LOG_ENTRY_CREATE" + GUILD_BAN_ADD EventType = "GUILD_BAN_ADD" + GUILD_BAN_REMOVE EventType = "GUILD_BAN_REMOVE" + GUILD_EMOJIS_UPDATE EventType = "GUILD_EMOJIS_UPDATE" + GUILD_STICKERS_UPDATE EventType = "GUILD_STICKERS_UPDATE" + GUILD_INTEGRATIONS_UPDATE EventType = "GUILD_INTEGRATIONS_UPDATE" + GUILD_MEMBER_ADD EventType = "GUILD_MEMBER_ADD" + GUILD_MEMBER_REMOVE EventType = "GUILD_MEMBER_REMOVE" + GUILD_MEMBER_UPDATE EventType = "GUILD_MEMBER_UPDATE" + GUILD_MEMBERS_CHUNK EventType = "GUILD_MEMBERS_CHUNK" + GUILD_ROLE_CREATE EventType = "GUILD_ROLE_CREATE" + GUILD_ROLE_UPDATE EventType = "GUILD_ROLE_UPDATE" + GUILD_ROLE_DELETE EventType = "GUILD_ROLE_DELETE" + GUILD_SCHEDULED_EVENT_CREATE EventType = "GUILD_SCHEDULED_EVENT_CREATE" + GUILD_SCHEDULED_EVENT_UPDATE EventType = "GUILD_SCHEDULED_EVENT_UPDATE" + GUILD_SCHEDULED_EVENT_DELETE EventType = "GUILD_SCHEDULED_EVENT_DELETE" + GUILD_SCHEDULED_EVENT_USER_ADD EventType = "GUILD_SCHEDULED_EVENT_USER_ADD" + GUILD_SCHEDULED_EVENT_USER_REMOVE EventType = "GUILD_SCHEDULED_EVENT_USER_REMOVE" + GUILD_SOUNDBOARD_SOUND_CREATE EventType = "GUILD_SOUNDBOARD_SOUND_CREATE" + GUILD_SOUNDBOARD_SOUND_UPDATE EventType = "GUILD_SOUNDBOARD_SOUND_UPDATE" + GUILD_SOUNDBOARD_SOUND_DELETE EventType = "GUILD_SOUNDBOARD_SOUND_DELETE" + GUILD_SOUNDBOARD_SOUNDS_UPDATE EventType = "GUILD_SOUNDBOARD_SOUNDS_UPDATE" + + SOUNDBOARD_SOUNDS EventType = "SOUNDBOARD_SOUNDS" + + INTEGRATION_CREATE EventType = "INTEGRATION_CREATE" + INTEGRATION_UPDATE EventType = "INTEGRATION_UPDATE" + INTEGRATION_DELETE EventType = "INTEGRATION_DELETE" + + INTERACTION_CREATE EventType = "INTERACTION_CREATE" + + INVITE_CREATE EventType = "INVITE_CREATE" + INVITE_DELETE EventType = "INVITE_DELETE" + MESSAGE_CREATE EventType = "MESSAGE_CREATE" MESSAGE_UPDATE EventType = "MESSAGE_UPDATE" MESSAGE_DELETE EventType = "MESSAGE_DELETE" @@ -38,16 +76,26 @@ const ( MESSAGE_REACTION_REMOVE EventType = "MESSAGE_REACTION_REMOVE" MESSAGE_REACTION_REMOVE_ALL EventType = "MESSAGE_REACTION_REMOVE_ALL" MESSAGE_REACTION_REMOVE_EMOJI EventType = "MESSAGE_REACTION_REMOVE_EMOJI" - PRESENCE_UPDATE EventType = "PRESENCE_UPDATE" - THREAD_CREATE EventType = "THREAD_CREATE" - THREAD_UPDATE EventType = "THREAD_UPDATE" - THREAD_DELETE EventType = "THREAD_DELETE" - THREAD_LIST_SYNC EventType = "THREAD_LIST_SYNC" - THREAD_MEMBER_UPDATE EventType = "THREAD_MEMBER_UPDATE" - THREAD_MEMBERS_UPDATE EventType = "THREAD_MEMBERS_UPDATE" - TYPING_START EventType = "TYPING_START" - USER_UPDATE EventType = "USER_UPDATE" - VOICE_STATE_UPDATE EventType = "VOICE_STATE_UPDATE" - VOICE_SERVER_UPDATE EventType = "VOICE_SERVER_UPDATE" - WEBHOOKS_UPDATE EventType = "WEBHOOKS_UPDATE" + MESSAGE_POLL_VOTE_ADD EventType = "MESSAGE_POLL_VOTE_ADD" + MESSAGE_POLL_VOTE_REMOVE EventType = "MESSAGE_POLL_VOTE_REMOVE" + + PRESENCE_UPDATE EventType = "PRESENCE_UPDATE" + + STAGE_INSTANCE_CREATE EventType = "STAGE_INSTANCE_CREATE" + STAGE_INSTANCE_UPDATE EventType = "STAGE_INSTANCE_UPDATE" + STAGE_INSTANCE_DELETE EventType = "STAGE_INSTANCE_DELETE" + + SUBSCRIPTION_CREATE EventType = "SUBSCRIPTION_CREATE" + SUBSCRIPTION_UPDATE EventType = "SUBSCRIPTION_UPDATE" + SUBSCRIPTION_DELETE EventType = "SUBSCRIPTION_DELETE" + + TYPING_START EventType = "TYPING_START" + + USER_UPDATE EventType = "USER_UPDATE" + + VOICE_CHANNEL_EFFECT_SEND EventType = "VOICE_CHANNEL_EFFECT_SEND" + VOICE_STATE_UPDATE EventType = "VOICE_STATE_UPDATE" + VOICE_SERVER_UPDATE EventType = "VOICE_SERVER_UPDATE" + + WEBHOOKS_UPDATE EventType = "WEBHOOKS_UPDATE" ) diff --git a/gateway/payloads/events/eventtypes.go b/gateway/payloads/events/eventtypes.go index 62d8d62..22c729a 100644 --- a/gateway/payloads/events/eventtypes.go +++ b/gateway/payloads/events/eventtypes.go @@ -7,19 +7,32 @@ type Event interface { Resumed | Reconnect | InvalidSession | + ApplicationCommandPermissionsUpdate | + AutoModerationRuleCreate | + AutoModerationRuleUpdate | + AutoModerationRuleDelete | + AutoModerationActionExecution | ChannelCreate | ChannelUpdate | ChannelDelete | ChannelPinsUpdate | + ThreadCreate | + ThreadUpdate | + ThreadDelete | + ThreadListSync | + ThreadMembersUpdate | + ThreadMemberUpdate | EntitlementCreate | EntitlementUpdate | EntitlementDelete | GuildCreate | GuildUpdate | GuildDelete | + GuildAuditLogEntryCreate | GuildBanAdd | GuildBanRemove | GuildEmojisUpdate | + GuildStickersUpdate | GuildIntegrationsUpdate | GuildMemberAdd | GuildMemberRemove | @@ -28,6 +41,19 @@ type Event interface { GuildRoleCreate | GuildRoleUpdate | GuildRoleDelete | + GuildScheduledEventCreate | + GuildScheduledEventUpdate | + GuildScheduledEventDelete | + GuildScheduledEventUserAdd | + GuildScheduledEventUserRemove | + GuildSoundboardSoundCreate | + GuildSoundboardSoundUpdate | + GuildSoundboardSoundDelete | + GuildSoundboardSoundsUpdate | + SoundboardSounds | + IntegrationCreate | + IntegrationUpdate | + IntegrationDelete | InviteCreate | InviteDelete | MessageCreate | @@ -38,48 +64,86 @@ type Event interface { MessageReactionRemove | MessageReactionRemoveAll | MessageReactionRemoveEmoji | + MessagePollVoteAdd | + MessagePollVoteRemove | PresenceUpdate | - ThreadCreate | - ThreadUpdate | - ThreadDelete | - ThreadListSync | - ThreadMembersUpdate | - ThreadMemberUpdate | + StageInstanceCreate | + StageInstanceUpdate | + StageInstanceDelete | + SubscriptionCreate | + SubscriptionUpdate | + SubscriptionDelete | TypingStart | UserUpdate | + VoiceChannelEffectSend | VoiceServerUpdate | VoiceStateUpdate | WebhooksUpdate } var EventTypes = map[EventType]reflect.Type{ - READY: reflect.TypeOf(Ready{}), - RESUMED: reflect.TypeOf(Resumed{}), - RECONNECT: reflect.TypeOf(Reconnect{}), - INVALID_SESSION: reflect.TypeOf(InvalidSession{}), - CHANNEL_CREATE: reflect.TypeOf(ChannelCreate{}), - CHANNEL_UPDATE: reflect.TypeOf(ChannelUpdate{}), - CHANNEL_DELETE: reflect.TypeOf(ChannelDelete{}), - CHANNEL_PINS_UPDATE: reflect.TypeOf(ChannelPinsUpdate{}), - ENTITLEMENT_CREATE: reflect.TypeOf(EntitlementCreate{}), - ENTITLEMENT_UPDATE: reflect.TypeOf(EntitlementUpdate{}), - ENTITLEMENT_DELETE: reflect.TypeOf(EntitlementDelete{}), - GUILD_CREATE: reflect.TypeOf(GuildCreate{}), - GUILD_UPDATE: reflect.TypeOf(GuildUpdate{}), - GUILD_DELETE: reflect.TypeOf(GuildDelete{}), - GUILD_BAN_ADD: reflect.TypeOf(GuildBanAdd{}), - GUILD_BAN_REMOVE: reflect.TypeOf(GuildBanRemove{}), - GUILD_EMOJIS_UPDATE: reflect.TypeOf(GuildEmojisUpdate{}), - GUILD_INTEGRATIONS_UPDATE: reflect.TypeOf(GuildIntegrationsUpdate{}), - GUILD_MEMBER_ADD: reflect.TypeOf(GuildMemberAdd{}), - GUILD_MEMBER_REMOVE: reflect.TypeOf(GuildMemberRemove{}), - GUILD_MEMBER_UPDATE: reflect.TypeOf(GuildMemberUpdate{}), - GUILD_MEMBERS_CHUNK: reflect.TypeOf(GuildMembersChunk{}), - GUILD_ROLE_CREATE: reflect.TypeOf(GuildRoleCreate{}), - GUILD_ROLE_UPDATE: reflect.TypeOf(GuildRoleUpdate{}), - GUILD_ROLE_DELETE: reflect.TypeOf(GuildRoleDelete{}), - INVITE_CREATE: reflect.TypeOf(InviteCreate{}), - INVITE_DELETE: reflect.TypeOf(InviteDelete{}), + READY: reflect.TypeOf(Ready{}), + RESUMED: reflect.TypeOf(Resumed{}), + RECONNECT: reflect.TypeOf(Reconnect{}), + INVALID_SESSION: reflect.TypeOf(InvalidSession{}), + + APPLICATION_COMMAND_PERMISSIONS_UPDATE: reflect.TypeOf(ApplicationCommandPermissionsUpdate{}), + + AUTO_MODERATION_RULE_CREATE: reflect.TypeOf(AutoModerationRuleCreate{}), + AUTO_MODERATION_RULE_UPDATE: reflect.TypeOf(AutoModerationRuleUpdate{}), + AUTO_MODERATION_RULE_DELETE: reflect.TypeOf(AutoModerationRuleDelete{}), + AUTO_MODERATION_ACTION_EXECUTION: reflect.TypeOf(AutoModerationActionExecution{}), + + CHANNEL_CREATE: reflect.TypeOf(ChannelCreate{}), + CHANNEL_UPDATE: reflect.TypeOf(ChannelUpdate{}), + CHANNEL_DELETE: reflect.TypeOf(ChannelDelete{}), + CHANNEL_PINS_UPDATE: reflect.TypeOf(ChannelPinsUpdate{}), + + THREAD_CREATE: reflect.TypeOf(ThreadCreate{}), + THREAD_UPDATE: reflect.TypeOf(ThreadUpdate{}), + THREAD_DELETE: reflect.TypeOf(ThreadDelete{}), + THREAD_LIST_SYNC: reflect.TypeOf(ThreadListSync{}), + THREAD_MEMBER_UPDATE: reflect.TypeOf(ThreadMemberUpdate{}), + THREAD_MEMBERS_UPDATE: reflect.TypeOf(ThreadMembersUpdate{}), + + ENTITLEMENT_CREATE: reflect.TypeOf(EntitlementCreate{}), + ENTITLEMENT_UPDATE: reflect.TypeOf(EntitlementUpdate{}), + ENTITLEMENT_DELETE: reflect.TypeOf(EntitlementDelete{}), + + GUILD_CREATE: reflect.TypeOf(GuildCreate{}), + GUILD_UPDATE: reflect.TypeOf(GuildUpdate{}), + GUILD_DELETE: reflect.TypeOf(GuildDelete{}), + GUILD_AUDIT_LOG_ENTRY_CREATE: reflect.TypeOf(GuildAuditLogEntryCreate{}), + GUILD_BAN_ADD: reflect.TypeOf(GuildBanAdd{}), + GUILD_BAN_REMOVE: reflect.TypeOf(GuildBanRemove{}), + GUILD_EMOJIS_UPDATE: reflect.TypeOf(GuildEmojisUpdate{}), + GUILD_STICKERS_UPDATE: reflect.TypeOf(GuildStickersUpdate{}), + GUILD_INTEGRATIONS_UPDATE: reflect.TypeOf(GuildIntegrationsUpdate{}), + GUILD_MEMBER_ADD: reflect.TypeOf(GuildMemberAdd{}), + GUILD_MEMBER_REMOVE: reflect.TypeOf(GuildMemberRemove{}), + GUILD_MEMBER_UPDATE: reflect.TypeOf(GuildMemberUpdate{}), + GUILD_MEMBERS_CHUNK: reflect.TypeOf(GuildMembersChunk{}), + GUILD_ROLE_CREATE: reflect.TypeOf(GuildRoleCreate{}), + GUILD_ROLE_UPDATE: reflect.TypeOf(GuildRoleUpdate{}), + GUILD_ROLE_DELETE: reflect.TypeOf(GuildRoleDelete{}), + GUILD_SCHEDULED_EVENT_CREATE: reflect.TypeOf(GuildScheduledEventCreate{}), + GUILD_SCHEDULED_EVENT_UPDATE: reflect.TypeOf(GuildScheduledEventUpdate{}), + GUILD_SCHEDULED_EVENT_DELETE: reflect.TypeOf(GuildScheduledEventDelete{}), + GUILD_SCHEDULED_EVENT_USER_ADD: reflect.TypeOf(GuildScheduledEventUserAdd{}), + GUILD_SCHEDULED_EVENT_USER_REMOVE: reflect.TypeOf(GuildScheduledEventUserRemove{}), + GUILD_SOUNDBOARD_SOUND_CREATE: reflect.TypeOf(GuildSoundboardSoundCreate{}), + GUILD_SOUNDBOARD_SOUND_UPDATE: reflect.TypeOf(GuildSoundboardSoundUpdate{}), + GUILD_SOUNDBOARD_SOUND_DELETE: reflect.TypeOf(GuildSoundboardSoundDelete{}), + GUILD_SOUNDBOARD_SOUNDS_UPDATE: reflect.TypeOf(GuildSoundboardSoundsUpdate{}), + SOUNDBOARD_SOUNDS: reflect.TypeOf(SoundboardSounds{}), + + INTEGRATION_CREATE: reflect.TypeOf(IntegrationCreate{}), + INTEGRATION_UPDATE: reflect.TypeOf(IntegrationUpdate{}), + INTEGRATION_DELETE: reflect.TypeOf(IntegrationDelete{}), + + INVITE_CREATE: reflect.TypeOf(InviteCreate{}), + INVITE_DELETE: reflect.TypeOf(InviteDelete{}), + MESSAGE_CREATE: reflect.TypeOf(MessageCreate{}), MESSAGE_UPDATE: reflect.TypeOf(MessageUpdate{}), MESSAGE_DELETE: reflect.TypeOf(MessageDelete{}), @@ -88,16 +152,26 @@ var EventTypes = map[EventType]reflect.Type{ MESSAGE_REACTION_REMOVE: reflect.TypeOf(MessageReactionRemove{}), MESSAGE_REACTION_REMOVE_ALL: reflect.TypeOf(MessageReactionRemoveAll{}), MESSAGE_REACTION_REMOVE_EMOJI: reflect.TypeOf(MessageReactionRemoveEmoji{}), - PRESENCE_UPDATE: reflect.TypeOf(PresenceUpdate{}), - THREAD_CREATE: reflect.TypeOf(ThreadCreate{}), - THREAD_UPDATE: reflect.TypeOf(ThreadUpdate{}), - THREAD_DELETE: reflect.TypeOf(ThreadDelete{}), - THREAD_LIST_SYNC: reflect.TypeOf(ThreadListSync{}), - THREAD_MEMBER_UPDATE: reflect.TypeOf(ThreadMemberUpdate{}), - THREAD_MEMBERS_UPDATE: reflect.TypeOf(ThreadMembersUpdate{}), - TYPING_START: reflect.TypeOf(TypingStart{}), - USER_UPDATE: reflect.TypeOf(UserUpdate{}), - VOICE_STATE_UPDATE: reflect.TypeOf(VoiceStateUpdate{}), - VOICE_SERVER_UPDATE: reflect.TypeOf(VoiceStateUpdate{}), - WEBHOOKS_UPDATE: reflect.TypeOf(WebhooksUpdate{}), + MESSAGE_POLL_VOTE_ADD: reflect.TypeOf(MessagePollVoteAdd{}), + MESSAGE_POLL_VOTE_REMOVE: reflect.TypeOf(MessagePollVoteRemove{}), + + PRESENCE_UPDATE: reflect.TypeOf(PresenceUpdate{}), + + STAGE_INSTANCE_CREATE: reflect.TypeOf(StageInstanceCreate{}), + STAGE_INSTANCE_UPDATE: reflect.TypeOf(StageInstanceUpdate{}), + STAGE_INSTANCE_DELETE: reflect.TypeOf(StageInstanceDelete{}), + + SUBSCRIPTION_CREATE: reflect.TypeOf(SubscriptionCreate{}), + SUBSCRIPTION_UPDATE: reflect.TypeOf(SubscriptionUpdate{}), + SUBSCRIPTION_DELETE: reflect.TypeOf(SubscriptionDelete{}), + + TYPING_START: reflect.TypeOf(TypingStart{}), + + USER_UPDATE: reflect.TypeOf(UserUpdate{}), + + VOICE_CHANNEL_EFFECT_SEND: reflect.TypeOf(VoiceChannelEffectSend{}), + VOICE_STATE_UPDATE: reflect.TypeOf(VoiceStateUpdate{}), + VOICE_SERVER_UPDATE: reflect.TypeOf(VoiceServerUpdate{}), + + WEBHOOKS_UPDATE: reflect.TypeOf(WebhooksUpdate{}), } diff --git a/gateway/payloads/events/guildauditlogentrycreate.go b/gateway/payloads/events/guildauditlogentrycreate.go new file mode 100644 index 0000000..8bca275 --- /dev/null +++ b/gateway/payloads/events/guildauditlogentrycreate.go @@ -0,0 +1,8 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/auditlog" + +type GuildAuditLogEntryCreate struct { + auditlog.AuditLogEntry + GuildId uint64 `json:"guild_id,string"` +} diff --git a/gateway/payloads/events/guildmemberschunk.go b/gateway/payloads/events/guildmemberschunk.go index 68f1443..95d43c3 100644 --- a/gateway/payloads/events/guildmemberschunk.go +++ b/gateway/payloads/events/guildmemberschunk.go @@ -7,8 +7,11 @@ import ( ) type GuildMembersChunk struct { - GuildId uint64 `json:"guild_id,string"` - Members []member.Member `json:"member"` - NotFound utils.Uint64StringSlice `json:"not_found"` - Presences []user.Presence `json:"presences"` + GuildId uint64 `json:"guild_id,string"` + Members []member.Member `json:"members"` + ChunkIndex int `json:"chunk_index"` + ChunkCount int `json:"chunk_count"` + NotFound utils.Uint64StringSlice `json:"not_found"` + Presences []user.Presence `json:"presences"` + Nonce string `json:"nonce"` } diff --git a/gateway/payloads/events/guildmemberupdate.go b/gateway/payloads/events/guildmemberupdate.go index 4f95253..c53bb20 100644 --- a/gateway/payloads/events/guildmemberupdate.go +++ b/gateway/payloads/events/guildmemberupdate.go @@ -8,9 +8,16 @@ import ( ) type GuildMemberUpdate struct { - GuildId uint64 `json:"guild_id,string"` - Roles utils.Uint64StringSlice `json:"roles"` - User user.User `json:"user"` - Nick string `json:"nick"` - PremiumSince *time.Time `json:"premium_since"` // When the user started boosting the guild + GuildId uint64 `json:"guild_id,string"` + Roles utils.Uint64StringSlice `json:"roles"` + User user.User `json:"user"` + Nick *string `json:"nick"` + Avatar *string `json:"avatar"` + Banner *string `json:"banner"` + JoinedAt *time.Time `json:"joined_at"` + PremiumSince *time.Time `json:"premium_since"` + Deaf *bool `json:"deaf"` + Mute *bool `json:"mute"` + Pending *bool `json:"pending"` + CommunicationDisabledUntil *time.Time `json:"communication_disabled_until"` } diff --git a/gateway/payloads/events/guildrolecreate.go b/gateway/payloads/events/guildrolecreate.go index c6fad49..0830c0c 100644 --- a/gateway/payloads/events/guildrolecreate.go +++ b/gateway/payloads/events/guildrolecreate.go @@ -6,5 +6,5 @@ import ( type GuildRoleCreate struct { GuildId uint64 `json:"guild_id,string"` - Role guild.Role ` json:"role"` + Role guild.Role `json:"role"` } diff --git a/gateway/payloads/events/guildroleupdate.go b/gateway/payloads/events/guildroleupdate.go index d077f52..b37a594 100644 --- a/gateway/payloads/events/guildroleupdate.go +++ b/gateway/payloads/events/guildroleupdate.go @@ -6,5 +6,5 @@ import ( type GuildRoleUpdate struct { GuildId uint64 `json:"guild_id,string"` - Role guild.Role ` json:"role"` + Role guild.Role `json:"role"` } diff --git a/gateway/payloads/events/guildscheduledevents.go b/gateway/payloads/events/guildscheduledevents.go new file mode 100644 index 0000000..e7ba6ec --- /dev/null +++ b/gateway/payloads/events/guildscheduledevents.go @@ -0,0 +1,27 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/guild/scheduledevent" + +type GuildScheduledEventCreate struct { + scheduledevent.GuildScheduledEvent +} + +type GuildScheduledEventUpdate struct { + scheduledevent.GuildScheduledEvent +} + +type GuildScheduledEventDelete struct { + scheduledevent.GuildScheduledEvent +} + +type GuildScheduledEventUserAdd struct { + GuildScheduledEventId uint64 `json:"guild_scheduled_event_id,string"` + UserId uint64 `json:"user_id,string"` + GuildId uint64 `json:"guild_id,string"` +} + +type GuildScheduledEventUserRemove struct { + GuildScheduledEventId uint64 `json:"guild_scheduled_event_id,string"` + UserId uint64 `json:"user_id,string"` + GuildId uint64 `json:"guild_id,string"` +} diff --git a/gateway/payloads/events/guildsoundboard.go b/gateway/payloads/events/guildsoundboard.go new file mode 100644 index 0000000..786a7a6 --- /dev/null +++ b/gateway/payloads/events/guildsoundboard.go @@ -0,0 +1,26 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/soundboard" + +type GuildSoundboardSoundCreate struct { + soundboard.SoundboardSound +} + +type GuildSoundboardSoundUpdate struct { + soundboard.SoundboardSound +} + +type GuildSoundboardSoundDelete struct { + SoundId uint64 `json:"sound_id,string"` + GuildId uint64 `json:"guild_id,string"` +} + +type GuildSoundboardSoundsUpdate struct { + GuildId uint64 `json:"guild_id,string"` + SoundboardSounds []soundboard.SoundboardSound `json:"soundboard_sounds"` +} + +type SoundboardSounds struct { + GuildId uint64 `json:"guild_id,string"` + SoundboardSounds []soundboard.SoundboardSound `json:"soundboard_sounds"` +} diff --git a/gateway/payloads/events/guildstickersupdate.go b/gateway/payloads/events/guildstickersupdate.go new file mode 100644 index 0000000..1e13238 --- /dev/null +++ b/gateway/payloads/events/guildstickersupdate.go @@ -0,0 +1,8 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/guild/sticker" + +type GuildStickersUpdate struct { + GuildId uint64 `json:"guild_id,string"` + Stickers []sticker.Sticker `json:"stickers"` +} diff --git a/gateway/payloads/events/integrations.go b/gateway/payloads/events/integrations.go new file mode 100644 index 0000000..9976214 --- /dev/null +++ b/gateway/payloads/events/integrations.go @@ -0,0 +1,19 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/integration" + +type IntegrationCreate struct { + integration.Integration + GuildId uint64 `json:"guild_id,string"` +} + +type IntegrationUpdate struct { + integration.Integration + GuildId uint64 `json:"guild_id,string"` +} + +type IntegrationDelete struct { + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + ApplicationId *uint64 `json:"application_id,string"` +} diff --git a/gateway/payloads/events/invitecreate.go b/gateway/payloads/events/invitecreate.go index dc069d1..bf4f747 100644 --- a/gateway/payloads/events/invitecreate.go +++ b/gateway/payloads/events/invitecreate.go @@ -1,14 +1,22 @@ package events -import "time" +import ( + "time" + + "github.com/TicketsBot-cloud/gdl/objects/user" +) type InviteCreate struct { - ChannelId uint64 `json:"channel_id,string"` - Code string `json:"code"` - CreatedAt time.Time `json:"created_at"` - GuildId uint64 `json:"guild_id,string"` - MaxAge int `json:"max_age"` // How long the invite is valid for, in seconds - MaxUses int `json:"max_uses"` - Temporary bool `json:"temporary"` - Uses int `json:"uses"` // Will always be 0 + ChannelId uint64 `json:"channel_id,string"` + Code string `json:"code"` + CreatedAt time.Time `json:"created_at"` + GuildId *uint64 `json:"guild_id,string"` + Inviter *user.User `json:"inviter"` + MaxAge int `json:"max_age"` + MaxUses int `json:"max_uses"` + TargetType *int `json:"target_type"` + TargetUser *user.User `json:"target_user"` + Temporary bool `json:"temporary"` + Uses int `json:"uses"` + ExpiresAt *time.Time `json:"expires_at"` } diff --git a/gateway/payloads/events/invitedelete.go b/gateway/payloads/events/invitedelete.go index 9a504c8..cc4a268 100644 --- a/gateway/payloads/events/invitedelete.go +++ b/gateway/payloads/events/invitedelete.go @@ -1,7 +1,7 @@ package events type InviteDelete struct { - ChannelId uint64 `json:"channel_id,string"` - GuildId uint64 `json:"guild_id,string"` - Code string `json:"code"` + ChannelId uint64 `json:"channel_id,string"` + GuildId *uint64 `json:"guild_id,string"` + Code string `json:"code"` } diff --git a/gateway/payloads/events/messagedelete.go b/gateway/payloads/events/messagedelete.go index 75cb07d..e575b0b 100644 --- a/gateway/payloads/events/messagedelete.go +++ b/gateway/payloads/events/messagedelete.go @@ -1,7 +1,7 @@ package events type MessageDelete struct { - Id uint64 `json:"id,string"` - ChannelId uint64 `json:"channel_id,string"` - GuildId uint64 `json:"guild_id,string"` + Id uint64 `json:"id,string"` + ChannelId uint64 `json:"channel_id,string"` + GuildId *uint64 `json:"guild_id,string"` } diff --git a/gateway/payloads/events/messagedeletebulk.go b/gateway/payloads/events/messagedeletebulk.go index 2f30c65..e4fdee0 100644 --- a/gateway/payloads/events/messagedeletebulk.go +++ b/gateway/payloads/events/messagedeletebulk.go @@ -3,7 +3,7 @@ package events import "github.com/TicketsBot-cloud/gdl/utils" type MessageDeleteBulk struct { - Id utils.Uint64StringSlice `json:"ids"` + Ids utils.Uint64StringSlice `json:"ids"` ChannelId uint64 `json:"channel_id,string"` - GuildId uint64 `json:"guild_id,string"` + GuildId *uint64 `json:"guild_id,string"` } diff --git a/gateway/payloads/events/messagepollvote.go b/gateway/payloads/events/messagepollvote.go new file mode 100644 index 0000000..7707876 --- /dev/null +++ b/gateway/payloads/events/messagepollvote.go @@ -0,0 +1,17 @@ +package events + +type MessagePollVoteAdd struct { + UserId uint64 `json:"user_id,string"` + ChannelId uint64 `json:"channel_id,string"` + MessageId uint64 `json:"message_id,string"` + GuildId *uint64 `json:"guild_id,string"` + AnswerId uint8 `json:"answer_id"` +} + +type MessagePollVoteRemove struct { + UserId uint64 `json:"user_id,string"` + ChannelId uint64 `json:"channel_id,string"` + MessageId uint64 `json:"message_id,string"` + GuildId *uint64 `json:"guild_id,string"` + AnswerId uint8 `json:"answer_id"` +} diff --git a/gateway/payloads/events/messagereactionadd.go b/gateway/payloads/events/messagereactionadd.go index 8d1fd35..d930dcc 100644 --- a/gateway/payloads/events/messagereactionadd.go +++ b/gateway/payloads/events/messagereactionadd.go @@ -6,10 +6,14 @@ import ( ) type MessageReactionAdd struct { - UserId uint64 `json:"user_id,string"` - ChannelId uint64 `json:"channel_id,string"` - MessageId uint64 `json:"message_id,string"` - GuildId uint64 `json:"guild_id,string"` - Member *member.Member `json:"member"` - Emoji emoji.Emoji `json:"emoji"` // Partial emoji object; https://discord.com/developers/docs/resources/emoji#emoji-object-gateway-reaction-standard-emoji-example + UserId uint64 `json:"user_id,string"` + ChannelId uint64 `json:"channel_id,string"` + MessageId uint64 `json:"message_id,string"` + GuildId *uint64 `json:"guild_id,string"` + MessageAuthorId *uint64 `json:"message_author_id,string"` + Member *member.Member `json:"member"` + Emoji emoji.Emoji `json:"emoji"` + Burst bool `json:"burst"` + BurstColors []string `json:"burst_colors"` + Type int `json:"type"` } diff --git a/gateway/payloads/events/messagereactionremove.go b/gateway/payloads/events/messagereactionremove.go index 7a07871..d47b665 100644 --- a/gateway/payloads/events/messagereactionremove.go +++ b/gateway/payloads/events/messagereactionremove.go @@ -1,14 +1,14 @@ package events -import ( - "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" -) +import "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" // Sent when a user removes a reaction from a message. type MessageReactionRemove struct { UserId uint64 `json:"user_id,string"` ChannelId uint64 `json:"channel_id,string"` MessageId uint64 `json:"message_id,string"` - GuildId uint64 `json:"guild_id,string"` - Emoji emoji.Emoji `json:"emoji,string"` // Partial emoji object; https://discord.com/developers/docs/resources/emoji#emoji-object-gateway-reaction-standard-emoji-example + GuildId *uint64 `json:"guild_id,string"` + Emoji emoji.Emoji `json:"emoji"` + Burst bool `json:"burst"` + Type int `json:"type"` } diff --git a/gateway/payloads/events/messagereactionremoveemoji.go b/gateway/payloads/events/messagereactionremoveemoji.go index f697ce8..8fda8c9 100644 --- a/gateway/payloads/events/messagereactionremoveemoji.go +++ b/gateway/payloads/events/messagereactionremoveemoji.go @@ -1,13 +1,11 @@ package events -import ( - "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" -) +import "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" // Sent when a bot removes all instances of a given emoji from the reactions of a message. type MessageReactionRemoveEmoji struct { ChannelId uint64 `json:"channel_id,string"` - GuildId uint64 `json:"guild_id,string"` + GuildId *uint64 `json:"guild_id,string"` MessageId uint64 `json:"message_id,string"` - Emoji emoji.Emoji `json:"emoji,string"` // Partial emoji object; https://discord.com/developers/docs/resources/emoji#emoji-object-gateway-reaction-standard-emoji-example + Emoji emoji.Emoji `json:"emoji"` } diff --git a/gateway/payloads/events/ready.go b/gateway/payloads/events/ready.go index 6f944ec..3d274ad 100644 --- a/gateway/payloads/events/ready.go +++ b/gateway/payloads/events/ready.go @@ -5,11 +5,17 @@ import ( "github.com/TicketsBot-cloud/gdl/objects/user" ) +type ReadyApplication struct { + Id uint64 `json:"id,string"` + Flags int `json:"flags"` +} + type Ready struct { - GatewayVersion int `json:"v"` - User user.User `json:"user"` - PrivateChannels []uint64 `json:"private_channels,string"` // Note: This slice will always be empty - Guilds []guild.Guild `json:"guilds"` - SessionId string `json:"session_id"` - Shard []int `json:"shard"` // Slice of [shard_id, num_shards] + GatewayVersion int `json:"v"` + User user.User `json:"user"` + Guilds []guild.Guild `json:"guilds"` + SessionId string `json:"session_id"` + ResumeGatewayUrl string `json:"resume_gateway_url"` + Shard []int `json:"shard"` + Application ReadyApplication `json:"application"` } diff --git a/gateway/payloads/events/stageinstances.go b/gateway/payloads/events/stageinstances.go new file mode 100644 index 0000000..aca5772 --- /dev/null +++ b/gateway/payloads/events/stageinstances.go @@ -0,0 +1,15 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/stage" + +type StageInstanceCreate struct { + stage.StageInstance +} + +type StageInstanceUpdate struct { + stage.StageInstance +} + +type StageInstanceDelete struct { + stage.StageInstance +} diff --git a/gateway/payloads/events/subscriptions.go b/gateway/payloads/events/subscriptions.go new file mode 100644 index 0000000..2501c47 --- /dev/null +++ b/gateway/payloads/events/subscriptions.go @@ -0,0 +1,15 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/subscription" + +type SubscriptionCreate struct { + subscription.Subscription +} + +type SubscriptionUpdate struct { + subscription.Subscription +} + +type SubscriptionDelete struct { + subscription.Subscription +} diff --git a/gateway/payloads/events/threadcreate.go b/gateway/payloads/events/threadcreate.go index 7cb9548..8b85097 100644 --- a/gateway/payloads/events/threadcreate.go +++ b/gateway/payloads/events/threadcreate.go @@ -1,9 +1,8 @@ package events -import ( - "github.com/TicketsBot-cloud/gdl/objects/channel" -) +import "github.com/TicketsBot-cloud/gdl/objects/channel" type ThreadCreate struct { channel.Channel + NewlyCreated bool `json:"newly_created"` } diff --git a/gateway/payloads/events/threaddelete.go b/gateway/payloads/events/threaddelete.go index d1f5753..5ff6cd4 100644 --- a/gateway/payloads/events/threaddelete.go +++ b/gateway/payloads/events/threaddelete.go @@ -1,9 +1,10 @@ package events -import ( - "github.com/TicketsBot-cloud/gdl/objects/channel" -) +import "github.com/TicketsBot-cloud/gdl/objects/channel" type ThreadDelete struct { - channel.Channel + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + ParentId uint64 `json:"parent_id,string"` + Type channel.ChannelType `json:"type"` } diff --git a/gateway/payloads/events/threadmembersupdate.go b/gateway/payloads/events/threadmembersupdate.go index 3287d29..1198cf8 100644 --- a/gateway/payloads/events/threadmembersupdate.go +++ b/gateway/payloads/events/threadmembersupdate.go @@ -8,7 +8,7 @@ import ( type ThreadMembersUpdate struct { ThreadId uint64 `json:"id,string"` GuildId uint64 `json:"guild_id,string"` - MemberCount uint64 `json:"member_count"` + MemberCount int `json:"member_count"` AddedMembers []channel.ThreadMember `json:"added_members"` RemovedMemberIds utils.Uint64StringSlice `json:"removed_member_ids"` } diff --git a/gateway/payloads/events/threadmemberupdate.go b/gateway/payloads/events/threadmemberupdate.go index 5bd444e..b1f1c71 100644 --- a/gateway/payloads/events/threadmemberupdate.go +++ b/gateway/payloads/events/threadmemberupdate.go @@ -1,9 +1,8 @@ package events -import ( - "github.com/TicketsBot-cloud/gdl/objects/channel" -) +import "github.com/TicketsBot-cloud/gdl/objects/channel" type ThreadMemberUpdate struct { channel.ThreadMember + GuildId uint64 `json:"guild_id,string"` } diff --git a/gateway/payloads/events/voicechanneleffectsend.go b/gateway/payloads/events/voicechanneleffectsend.go new file mode 100644 index 0000000..fd338a7 --- /dev/null +++ b/gateway/payloads/events/voicechanneleffectsend.go @@ -0,0 +1,14 @@ +package events + +import "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" + +type VoiceChannelEffectSend struct { + ChannelId uint64 `json:"channel_id,string"` + GuildId uint64 `json:"guild_id,string"` + UserId uint64 `json:"user_id,string"` + Emoji *emoji.Emoji `json:"emoji"` + AnimationType *int `json:"animation_type"` + AnimationId uint `json:"animation_id"` + SoundId *uint64 `json:"sound_id,string"` + SoundVolume *float64 `json:"sound_volume"` +} diff --git a/gateway/payloads/events/voiceserverupdate.go b/gateway/payloads/events/voiceserverupdate.go index 9f8d59b..6a59bcf 100644 --- a/gateway/payloads/events/voiceserverupdate.go +++ b/gateway/payloads/events/voiceserverupdate.go @@ -3,5 +3,5 @@ package events type VoiceServerUpdate struct { Token string `json:"token"` GuildId uint64 `json:"guild_id,string"` - Endpoint string `json:"endpoint"` + Endpoint *string `json:"endpoint"` } diff --git a/gateway/restwrapper.go b/gateway/restwrapper.go index d32b6ee..41f9bae 100644 --- a/gateway/restwrapper.go +++ b/gateway/restwrapper.go @@ -395,7 +395,7 @@ func (s *Shard) SearchGuildMembers(ctx context.Context, guildId uint64, data res var users []user.User for _, m := range members { - users = append(users, m.User) + users = append(users, *m.User) } if err := s.Cache.StoreUsers(ctx, users); err != nil { @@ -419,7 +419,7 @@ func (s *Shard) ListGuildMembers(ctx context.Context, guildId uint64, data rest. var users []user.User for _, m := range members { - users = append(users, m.User) + users = append(users, *m.User) } if err := s.Cache.StoreUsers(ctx, users); err != nil { diff --git a/objects/automoderation/automoderation.go b/objects/automoderation/automoderation.go new file mode 100644 index 0000000..b4d5a95 --- /dev/null +++ b/objects/automoderation/automoderation.go @@ -0,0 +1,61 @@ +package automoderation + +type EventType int + +const ( + EventTypeMessageSend EventType = 1 + EventTypeMemberUpdate EventType = 2 +) + +type TriggerType int + +const ( + TriggerTypeKeyword TriggerType = 1 + TriggerTypeSpam TriggerType = 3 + TriggerTypeKeywordPreset TriggerType = 4 + TriggerTypeMentionSpam TriggerType = 5 + TriggerTypeMemberProfile TriggerType = 6 +) + +type ActionType int + +const ( + ActionTypeBlockMessage ActionType = 1 + ActionTypeSendAlertMessage ActionType = 2 + ActionTypeTimeout ActionType = 3 + ActionTypeBlockMemberInteraction ActionType = 4 +) + +type TriggerMetadata struct { + KeywordFilter []string `json:"keyword_filter"` + RegexPatterns []string `json:"regex_patterns"` + Presets []int `json:"presets"` + AllowList []string `json:"allow_list"` + MentionTotalLimit int `json:"mention_total_limit"` + MentionRaidProtectionEnabled bool `json:"mention_raid_protection_enabled"` +} + +type ActionMetadata struct { + ChannelId uint64 `json:"channel_id,string"` + DurationSeconds int `json:"duration_seconds"` + CustomMessage *string `json:"custom_message,omitempty"` +} + +type Action struct { + Type ActionType `json:"type"` + Metadata *ActionMetadata `json:"metadata,omitempty"` +} + +type Rule struct { + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + Name string `json:"name"` + CreatorId uint64 `json:"creator_id,string"` + EventType EventType `json:"event_type"` + TriggerType TriggerType `json:"trigger_type"` + TriggerMetadata TriggerMetadata `json:"trigger_metadata"` + Actions []Action `json:"actions"` + Enabled bool `json:"enabled"` + ExemptRoles []uint64 `json:"exempt_roles"` + ExemptChannels []uint64 `json:"exempt_channels"` +} diff --git a/objects/guild/cachedvoicestate.go b/objects/guild/cachedvoicestate.go index 8e40b04..2f33f55 100644 --- a/objects/guild/cachedvoicestate.go +++ b/objects/guild/cachedvoicestate.go @@ -1,8 +1,6 @@ package guild -import ( - "github.com/TicketsBot-cloud/gdl/objects/member" -) +import "github.com/TicketsBot-cloud/gdl/objects/member" type CachedVoiceState struct { ChannelId uint64 `json:"channel_id"` @@ -15,11 +13,17 @@ type CachedVoiceState struct { } func (s *CachedVoiceState) ToVoiceState(guildId uint64, m member.Member) VoiceState { + channelId := s.ChannelId + var userId uint64 + if m.User != nil { + userId = m.User.Id + } + return VoiceState{ - GuildId: guildId, - ChannelId: s.ChannelId, - UserId: m.User.Id, - Member: m, + GuildId: &guildId, + ChannelId: &channelId, + UserId: userId, + Member: &m, SessionId: s.SessionId, Deaf: s.Deaf, Mute: s.Mute, diff --git a/objects/guild/guild.go b/objects/guild/guild.go index bf107c9..a3affdd 100644 --- a/objects/guild/guild.go +++ b/objects/guild/guild.go @@ -39,7 +39,7 @@ type Guild struct { Large bool `json:"large"` Unavailable *bool `json:"unavailable"` MemberCount int `json:"member_count"` - VoiceStates []VoiceState `json:"voice_state"` + VoiceStates []VoiceState `json:"voice_states"` Members []member.Member `json:"members"` Channels []channel.Channel `json:"channels"` Threads []channel.Channel `json:"threads"` diff --git a/objects/guild/role.go b/objects/guild/role.go index d603340..c3c5704 100644 --- a/objects/guild/role.go +++ b/objects/guild/role.go @@ -1,19 +1,20 @@ package guild -import ( - "fmt" -) +import "fmt" type Role struct { - Id uint64 `json:"id,string"` - Name string `json:"name"` - Color int `json:"color"` - Hoist bool `json:"hoist"` - Position int `json:"position"` - Permissions uint64 `json:"permissions,string"` - Managed bool `json:"managed"` - Mentionable bool `json:"mentionable"` - Tags RoleTags `json:"tags"` + Id uint64 `json:"id,string"` + Name string `json:"name"` + Color int `json:"color"` + Hoist bool `json:"hoist"` + Icon *string `json:"icon"` + UnicodeEmoji *string `json:"unicode_emoji"` + Position int `json:"position"` + Permissions uint64 `json:"permissions,string"` + Managed bool `json:"managed"` + Mentionable bool `json:"mentionable"` + Flags int `json:"flags"` + Tags RoleTags `json:"tags"` } type RoleTags struct { diff --git a/objects/guild/scheduledevent/scheduledevent.go b/objects/guild/scheduledevent/scheduledevent.go new file mode 100644 index 0000000..42c8f27 --- /dev/null +++ b/objects/guild/scheduledevent/scheduledevent.go @@ -0,0 +1,53 @@ +package scheduledevent + +import ( + "time" + + "github.com/TicketsBot-cloud/gdl/objects/user" +) + +type PrivacyLevel int + +const ( + PrivacyLevelGuildOnly PrivacyLevel = 2 +) + +type EntityType int + +const ( + EntityTypeStageInstance EntityType = iota + 1 + EntityTypeVoice + EntityTypeExternal +) + +type Status int + +const ( + StatusScheduled Status = iota + 1 + StatusActive + StatusCompleted + StatusCanceled +) + +type EntityMetadata struct { + Location *string `json:"location,omitempty"` +} + +type GuildScheduledEvent struct { + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + ChannelId *uint64 `json:"channel_id,string"` + CreatorId *uint64 `json:"creator_id,string"` + Name string `json:"name"` + Description *string `json:"description,omitempty"` + ScheduledStartTime time.Time `json:"scheduled_start_time"` + ScheduledEndTime *time.Time `json:"scheduled_end_time,omitempty"` + PrivacyLevel PrivacyLevel `json:"privacy_level"` + Status Status `json:"status"` + EntityType EntityType `json:"entity_type"` + EntityId *uint64 `json:"entity_id,string"` + EntityMetadata *EntityMetadata `json:"entity_metadata,omitempty"` + Creator *user.User `json:"creator,omitempty"` + UserCount *int `json:"user_count,omitempty"` + Image *string `json:"image,omitempty"` +} diff --git a/objects/guild/sticker/sticker.go b/objects/guild/sticker/sticker.go new file mode 100644 index 0000000..da0ff3a --- /dev/null +++ b/objects/guild/sticker/sticker.go @@ -0,0 +1,33 @@ +package sticker + +import "github.com/TicketsBot-cloud/gdl/objects/user" + +type StickerType int + +const ( + StickerTypeStandard StickerType = iota + 1 + StickerTypeGuild +) + +type StickerFormatType int + +const ( + StickerFormatTypePNG StickerFormatType = iota + 1 + StickerFormatTypeAPNG + StickerFormatTypeLottie + StickerFormatTypeGIF +) + +type Sticker struct { + Id uint64 `json:"id,string"` + PackId *uint64 `json:"pack_id,string"` + Name string `json:"name"` + Description *string `json:"description"` + Tags string `json:"tags"` + Type StickerType `json:"type"` + FormatType StickerFormatType `json:"format_type"` + Available *bool `json:"available"` + GuildId *uint64 `json:"guild_id,string"` + User *user.User `json:"user"` + SortValue *int `json:"sort_value"` +} diff --git a/objects/guild/voicestate.go b/objects/guild/voicestate.go index a29fdf0..173325a 100644 --- a/objects/guild/voicestate.go +++ b/objects/guild/voicestate.go @@ -1,23 +1,35 @@ package guild -import "github.com/TicketsBot-cloud/gdl/objects/member" +import ( + "time" + + "github.com/TicketsBot-cloud/gdl/objects/member" +) type VoiceState struct { - GuildId uint64 `json:"guild_id,string"` - ChannelId uint64 `json:"channel_id,string"` - UserId uint64 `json:"user_id,string"` - Member member.Member `json:"member"` - SessionId string `json:"session_id"` - Deaf bool `json:"deaf"` - Mute bool `json:"mute"` - SelfDeaf bool `json:"self_deaf"` - SelfMute bool `json:"self_mute"` - Suppress bool `json:"suppress"` + GuildId *uint64 `json:"guild_id,string"` + ChannelId *uint64 `json:"channel_id,string"` + UserId uint64 `json:"user_id,string"` + Member *member.Member `json:"member"` + SessionId string `json:"session_id"` + Deaf bool `json:"deaf"` + Mute bool `json:"mute"` + SelfDeaf bool `json:"self_deaf"` + SelfMute bool `json:"self_mute"` + SelfStream bool `json:"self_stream"` + SelfVideo bool `json:"self_video"` + Suppress bool `json:"suppress"` + RequestToSpeakTimestamp *time.Time `json:"request_to_speak_timestamp"` } func (s *VoiceState) ToCachedVoiceState() CachedVoiceState { + var channelId uint64 + if s.ChannelId != nil { + channelId = *s.ChannelId + } + return CachedVoiceState{ - ChannelId: s.ChannelId, + ChannelId: channelId, SessionId: s.SessionId, Deaf: s.Deaf, Mute: s.Mute, diff --git a/objects/interaction/applicationcommandpermissions.go b/objects/interaction/applicationcommandpermissions.go index da7bf83..a669b66 100644 --- a/objects/interaction/applicationcommandpermissions.go +++ b/objects/interaction/applicationcommandpermissions.go @@ -3,8 +3,9 @@ package interaction type ApplicationCommandPermissionType uint8 const ( - ApplicationCommandPermissionTypeRole ApplicationCommandPermissionType = iota + 1 + ApplicationCommandPermissionTypeRole ApplicationCommandPermissionType = iota + 1 ApplicationCommandPermissionTypeUser + ApplicationCommandPermissionTypeChannel ) type ApplicationCommandPermissions struct { @@ -12,3 +13,10 @@ type ApplicationCommandPermissions struct { Type ApplicationCommandPermissionType `json:"type"` Permission bool `json:"permission"` } + +type GuildApplicationCommandPermissions struct { + Id uint64 `json:"id,string"` + ApplicationId uint64 `json:"application_id,string"` + GuildId uint64 `json:"guild_id,string"` + Permissions []ApplicationCommandPermissions `json:"permissions"` +} diff --git a/objects/member/cachedmember.go b/objects/member/cachedmember.go index 5b5f956..e7b82a2 100644 --- a/objects/member/cachedmember.go +++ b/objects/member/cachedmember.go @@ -7,20 +7,20 @@ import ( ) type CachedMember struct { - Nick string `json:"nick"` + Nick *string `json:"nick"` Roles []uint64 `json:"roles"` JoinedAt time.Time `json:"joined_at"` - PremiumSince *time.Time `json:"premium_since"` // when the user started boosting the guild + PremiumSince *time.Time `json:"premium_since"` Deaf bool `json:"deaf"` Mute bool `json:"mute"` } -func (m *CachedMember) ToMember(user user.User) Member { +func (m *CachedMember) ToMember(u user.User) Member { return Member{ - User: user, + User: &u, Nick: m.Nick, Roles: m.Roles, - JoinedAt: m.JoinedAt, + JoinedAt: &m.JoinedAt, PremiumSince: m.PremiumSince, Deaf: m.Deaf, Mute: m.Mute, diff --git a/objects/member/member.go b/objects/member/member.go index 3be6383..6b7f0af 100644 --- a/objects/member/member.go +++ b/objects/member/member.go @@ -8,14 +8,19 @@ import ( ) type Member struct { - User user.User `json:"user"` - Nick string `json:"nick"` - Roles utils.Uint64StringSlice `json:"roles"` - JoinedAt time.Time `json:"joined_at"` - PremiumSince *time.Time `json:"premium_since"` // when the user started boosting the guild - Deaf bool `json:"deaf"` - Mute bool `json:"mute"` - Permissions uint64 `json:"permissions,string"` + User *user.User `json:"user"` + Nick *string `json:"nick"` + Avatar *string `json:"avatar"` + Banner *string `json:"banner"` + Roles utils.Uint64StringSlice `json:"roles"` + JoinedAt *time.Time `json:"joined_at"` + PremiumSince *time.Time `json:"premium_since"` + Deaf bool `json:"deaf"` + Mute bool `json:"mute"` + Flags int `json:"flags"` + Pending *bool `json:"pending"` + Permissions uint64 `json:"permissions,string"` + CommunicationDisabledUntil *time.Time `json:"communication_disabled_until"` } func (m *Member) HasRole(roleId uint64) bool { @@ -28,10 +33,15 @@ func (m *Member) HasRole(roleId uint64) bool { } func (m *Member) ToCachedMember() CachedMember { + var joinedAt time.Time + if m.JoinedAt != nil { + joinedAt = *m.JoinedAt + } + return CachedMember{ Nick: m.Nick, Roles: m.Roles, - JoinedAt: m.JoinedAt, + JoinedAt: joinedAt, PremiumSince: m.PremiumSince, Deaf: m.Deaf, Mute: m.Mute, diff --git a/objects/soundboard/soundboard.go b/objects/soundboard/soundboard.go new file mode 100644 index 0000000..e9d4c6a --- /dev/null +++ b/objects/soundboard/soundboard.go @@ -0,0 +1,14 @@ +package soundboard + +import "github.com/TicketsBot-cloud/gdl/objects/user" + +type SoundboardSound struct { + SoundId uint64 `json:"sound_id,string"` + Name string `json:"name"` + Volume float64 `json:"volume"` + EmojiId *uint64 `json:"emoji_id,string"` + EmojiName *string `json:"emoji_name,omitempty"` + GuildId *uint64 `json:"guild_id,string"` + Available bool `json:"available"` + User *user.User `json:"user,omitempty"` +} diff --git a/objects/stage/stage.go b/objects/stage/stage.go new file mode 100644 index 0000000..9f09d0c --- /dev/null +++ b/objects/stage/stage.go @@ -0,0 +1,11 @@ +package stage + +type StageInstance struct { + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + ChannelId uint64 `json:"channel_id,string"` + Topic string `json:"topic"` + PrivacyLevel int `json:"privacy_level"` + DiscoverableDisabled bool `json:"discoverable_disabled"` + GuildScheduledEventId *uint64 `json:"guild_scheduled_event_id,string"` +} diff --git a/objects/subscription/subscription.go b/objects/subscription/subscription.go new file mode 100644 index 0000000..1a27d7f --- /dev/null +++ b/objects/subscription/subscription.go @@ -0,0 +1,28 @@ +package subscription + +import ( + "time" + + "github.com/TicketsBot-cloud/gdl/utils" +) + +type Status int + +const ( + StatusActive Status = iota + StatusEnding + StatusInactive +) + +type Subscription struct { + Id uint64 `json:"id,string"` + UserId uint64 `json:"user_id,string"` + SkuIds utils.Uint64StringSlice `json:"sku_ids"` + EntitlementIds utils.Uint64StringSlice `json:"entitlement_ids"` + RenewalSkuIds utils.Uint64StringSlice `json:"renewal_sku_ids"` + CurrentPeriodStart time.Time `json:"current_period_start"` + CurrentPeriodEnd time.Time `json:"current_period_end"` + Status Status `json:"status"` + CanceledAt *time.Time `json:"canceled_at,omitempty"` + Country *string `json:"country,omitempty"` +} From 74004b1c16b19198f24d4cacdfb72a36dbe7dee5 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 20:10:31 +0100 Subject: [PATCH 05/73] Make ThreadMember IDs optional and add Member Change ThreadMember.ThreadId and ThreadMember.UserId to pointer types with `omitempty` so they can be absent in JSON payloads, and add a Member field (`*member.Member`) to include embedded member data. Also update imports to include the member package. Other fields and behavior remain unchanged. --- objects/channel/thread.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/objects/channel/thread.go b/objects/channel/thread.go index 48f68ee..42d3db9 100644 --- a/objects/channel/thread.go +++ b/objects/channel/thread.go @@ -1,6 +1,10 @@ package channel -import "time" +import ( + "time" + + "github.com/TicketsBot-cloud/gdl/objects/member" +) type ThreadMetadata struct { Archived bool `json:"archived"` @@ -12,8 +16,9 @@ type ThreadMetadata struct { } type ThreadMember struct { - ThreadId uint64 `json:"id,string"` - UserId uint64 `json:"user_id,string"` - JoinTimestamp time.Time `json:"join_timestamp"` - Flags uint `json:"flags"` + ThreadId *uint64 `json:"id,string,omitempty"` + UserId *uint64 `json:"user_id,string,omitempty"` + JoinTimestamp time.Time `json:"join_timestamp"` + Flags uint `json:"flags"` + Member *member.Member `json:"member,omitempty"` } From 02cb93cfa0bcb4838c0b3b574beaeb3a14060727 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 20:20:26 +0100 Subject: [PATCH 06/73] Simplify PartialChannel and ToPartialChannel Reduce PartialChannel to only Id, Type and an optional Name pointer, and update Channel.ToPartialChannel to populate the new shape. Removed several fields (GuildId, Position, Topic, Nsfw, LastMessageId, ParentId, LastPinTimestamp) and unused imports (time, objects). This makes the partial channel payload smaller and allows Name to be omitted when empty via the pointer and `omitempty` JSON tag. https://discord-api-types.dev/api/discord-api-types-v10/interface/APIPartialChannel --- objects/channel/channel.go | 13 +++---------- objects/channel/partialchannel.go | 19 +++---------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/objects/channel/channel.go b/objects/channel/channel.go index 57d249c..961cdc0 100644 --- a/objects/channel/channel.go +++ b/objects/channel/channel.go @@ -62,15 +62,8 @@ func (c *Channel) ToCachedChannel() CachedChannel { func (c *Channel) ToPartialChannel() PartialChannel { return PartialChannel{ - Id: c.Id, - Type: c.Type, - GuildId: c.GuildId, - Position: c.Position, - Name: c.Name, - Topic: c.Topic, - Nsfw: c.Nsfw, - LastMessageId: c.LastMessageId, - ParentId: c.ParentId, - LastPinTimestamp: c.LastPinTimestamp, + Id: c.Id, + Type: c.Type, + Name: &c.Name, } } diff --git a/objects/channel/partialchannel.go b/objects/channel/partialchannel.go index 365a674..2bd10fc 100644 --- a/objects/channel/partialchannel.go +++ b/objects/channel/partialchannel.go @@ -1,20 +1,7 @@ package channel -import ( - "time" - - "github.com/TicketsBot-cloud/gdl/objects" -) - type PartialChannel struct { - Id uint64 `json:"id,string"` - Type ChannelType `json:"type"` - GuildId uint64 `json:"guild_id,string"` - Position int `json:"position"` - Name string `json:"name"` - Topic string `json:"topic"` - Nsfw bool `json:"nsfw"` - LastMessageId objects.NullableSnowflake `json:"last_message_id"` - ParentId objects.NullableSnowflake `json:"parent_id,omitempty"` - LastPinTimestamp time.Time `json:"last_pin_timestamp"` + Id uint64 `json:"id,string"` + Type ChannelType `json:"type"` + Name *string `json:"name,omitempty"` } From f76ea3129bcbcd3be7581d5c82b81a130e2592ca Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 20:24:19 +0100 Subject: [PATCH 07/73] Fix short time timestamp style constant https://docs.discord.com/developers/reference#message-formatting-timestamp-styles --- objects/channel/message/timestamp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objects/channel/message/timestamp.go b/objects/channel/message/timestamp.go index b091c42..7aec44d 100644 --- a/objects/channel/message/timestamp.go +++ b/objects/channel/message/timestamp.go @@ -8,7 +8,7 @@ import ( type TimestampStyle string const ( - TimestampStyleShortTime TimestampStyle = "s" + TimestampStyleShortTime TimestampStyle = "t" TimestampStyleLongTime TimestampStyle = "T" TimestampStyleShortDate TimestampStyle = "d" TimestampStyleLongDate TimestampStyle = "D" From 7aefa7c827c25175d6422e3661413e704a3670ca Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 20:26:49 +0100 Subject: [PATCH 08/73] Add burst reaction details to Reaction struct https://docs.discord.com/developers/resources/message#reaction-object --- objects/channel/message/reaction.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/objects/channel/message/reaction.go b/objects/channel/message/reaction.go index 8a9c76d..74f4172 100644 --- a/objects/channel/message/reaction.go +++ b/objects/channel/message/reaction.go @@ -2,8 +2,16 @@ package message import "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" +type ReactionCountDetails struct { + Burst int `json:"burst"` + Normal int `json:"normal"` +} + type Reaction struct { - Count int - Me bool - Emoji emoji.Emoji + Count int `json:"count"` + CountDetails ReactionCountDetails `json:"count_details"` + Me bool `json:"me"` + MeBurst bool `json:"me_burst"` + Emoji emoji.Emoji `json:"emoji"` + BurstColors []string `json:"burst_colors"` } From 9ce509edbc9386559e0deaf5b52422dbf0f73202 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 21:02:47 +0100 Subject: [PATCH 09/73] Enhance Message struct and add message types Revamp the Message model to better mirror the API and support newer message features: make many fields optional/pointer types and add/rename fields (guild_id, webhook_id, application_id, message_snapshots, interaction_metadata, sticker_items, stickers, position, role_subscription_data, poll, call, etc.). Add new message-related types and files: MessageCall, MessageInteraction (deprecated) and MessageInteractionMetadata, MessageSnapshot, Poll (+ related structs), RoleSubscriptionData, and StickerItem. Also adjust smaller types: MessageActivity.PartyId is now optional, MessageApplication uses pointer fields for nullable values, MessageReference fields are optional, and MessageMentionedUser.Member is now a pointer. These changes improve API parity and enable handling of newer Discord message payloads. https://docs.discord.com/developers/resources/message#message-object --- objects/channel/message/message.go | 64 +++++++++++-------- objects/channel/message/messageactivity.go | 2 +- objects/channel/message/messageapplication.go | 10 +-- objects/channel/message/messagecall.go | 12 ++++ objects/channel/message/messageinteraction.go | 26 ++++++++ .../channel/message/messagementioneduser.go | 2 +- objects/channel/message/messagereference.go | 9 +-- objects/channel/message/messagesnapshot.go | 5 ++ objects/channel/message/poll.go | 37 +++++++++++ .../channel/message/rolesubscriptiondata.go | 8 +++ objects/channel/message/stickeritem.go | 9 +++ 11 files changed, 147 insertions(+), 37 deletions(-) create mode 100644 objects/channel/message/messagecall.go create mode 100644 objects/channel/message/messageinteraction.go create mode 100644 objects/channel/message/messagesnapshot.go create mode 100644 objects/channel/message/poll.go create mode 100644 objects/channel/message/rolesubscriptiondata.go create mode 100644 objects/channel/message/stickeritem.go diff --git a/objects/channel/message/message.go b/objects/channel/message/message.go index ffb4a26..4f549f2 100644 --- a/objects/channel/message/message.go +++ b/objects/channel/message/message.go @@ -7,6 +7,7 @@ import ( "github.com/TicketsBot-cloud/gdl/objects/channel" "github.com/TicketsBot-cloud/gdl/objects/channel/embed" + "github.com/TicketsBot-cloud/gdl/objects/guild/sticker" "github.com/TicketsBot-cloud/gdl/objects/interaction/component" "github.com/TicketsBot-cloud/gdl/objects/member" "github.com/TicketsBot-cloud/gdl/objects/user" @@ -14,32 +15,43 @@ import ( ) type Message struct { - Id uint64 `json:"id,string"` - ChannelId uint64 `json:"channel_id,string"` - GuildId uint64 `json:"guild_id,string"` - Author user.User `json:"author"` - Member member.Member `json:"member"` - Content string `json:"content"` - Timestamp time.Time `json:"timestamp"` - EditedTimestamp *time.Time `json:"edited_timestamp,omitempty"` - Tts bool `json:"tts"` - MentionEveryone bool `json:"mention_everyone"` - Mentions []MessageMentionedUser `json:"mentions,omitempty"` // The user objects in the mentions array will only have the partial member field present in MESSAGE_CREATE and MESSAGE_UPDATE events from text-based guild channels - MentionRoles utils.Uint64StringSlice `json:"mention_roles"` - VisibleMentionedChannels []ChannelMention `json:"mention_channels,omitempty"` // Not all channel mentions in a message will appear in mention_channels. Only textual channels that are visible to everyone in a lurkable guild will ever be included. Only crossposted messages (via Channel Following) currently include mention_channels at all. If no mentions in the message meet these requirements, this field will not be sent. - Attachments []channel.Attachment `json:"attachments,omitempty"` - Embeds []embed.Embed `json:"embeds,omitempty"` - Reactions []Reaction `json:"reactions,omitempty"` - Nonce interface{} `json:"nonce,omitempty"` - Pinned bool `json:"pinned"` - WebhookId uint64 `json:"webhook_id,string"` // if the message is generated by a webhook, this is the webhook's id - Type MessageType `json:"message_type"` - Activity MessageActivity `json:"activity"` - Application MessageApplication `json:"application"` - MessageReference MessageReference `json:"message_reference"` // reference data sent with crossposted messages - Flags int `json:"flags"` - ReferencedMessage *MessageReference `json:"referenced_message,omitempty"` - Components []component.Component `json:"components,omitempty"` + Id uint64 `json:"id,string"` + ChannelId uint64 `json:"channel_id,string"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + Author user.User `json:"author"` + Member *member.Member `json:"member,omitempty"` + Content string `json:"content"` + Timestamp time.Time `json:"timestamp"` + EditedTimestamp *time.Time `json:"edited_timestamp,omitempty"` + Tts bool `json:"tts"` + MentionEveryone bool `json:"mention_everyone"` + Mentions []MessageMentionedUser `json:"mentions,omitempty"` // The user objects in the mentions array will only have the partial member field present in MESSAGE_CREATE and MESSAGE_UPDATE events from text-based guild channels + MentionRoles utils.Uint64StringSlice `json:"mention_roles"` + MentionChannels []ChannelMention `json:"mention_channels,omitempty"` // Not all channel mentions in a message will appear in mention_channels. Only textual channels that are visible to everyone in a lurkable guild will ever be included. + Attachments []channel.Attachment `json:"attachments,omitempty"` + Embeds []embed.Embed `json:"embeds,omitempty"` + Reactions []Reaction `json:"reactions,omitempty"` + Nonce interface{} `json:"nonce,omitempty"` + Pinned bool `json:"pinned"` + WebhookId *uint64 `json:"webhook_id,string,omitempty"` + Type MessageType `json:"type"` + Activity *MessageActivity `json:"activity,omitempty"` + Application *MessageApplication `json:"application,omitempty"` + ApplicationId *uint64 `json:"application_id,string,omitempty"` + Flags MessageFlag `json:"flags,omitempty"` + MessageReference *MessageReference `json:"message_reference,omitempty"` + MessageSnapshots []MessageSnapshot `json:"message_snapshots,omitempty"` + ReferencedMessage *Message `json:"referenced_message,omitempty"` + InteractionMetadata *MessageInteractionMetadata `json:"interaction_metadata,omitempty"` + Interaction *MessageInteraction `json:"interaction,omitempty"` // Deprecated: use InteractionMetadata + Thread *channel.Channel `json:"thread,omitempty"` + Components []component.Component `json:"components,omitempty"` + StickerItems []StickerItem `json:"sticker_items,omitempty"` + Stickers []sticker.Sticker `json:"stickers,omitempty"` + Position *int `json:"position,omitempty"` + RoleSubscriptionData *RoleSubscriptionData `json:"role_subscription_data,omitempty"` + Poll *Poll `json:"poll,omitempty"` + Call *MessageCall `json:"call,omitempty"` } var channelMentionRegex = regexp.MustCompile(`<#(\d+)>`) diff --git a/objects/channel/message/messageactivity.go b/objects/channel/message/messageactivity.go index e83cb0f..8a41d98 100644 --- a/objects/channel/message/messageactivity.go +++ b/objects/channel/message/messageactivity.go @@ -2,5 +2,5 @@ package message type MessageActivity struct { Type MessageActivityType `json:"type"` - PartyId string `json:"party_id"` + PartyId *string `json:"party_id,omitempty"` } diff --git a/objects/channel/message/messageapplication.go b/objects/channel/message/messageapplication.go index 6ebb857..84836d4 100644 --- a/objects/channel/message/messageapplication.go +++ b/objects/channel/message/messageapplication.go @@ -1,9 +1,9 @@ package message type MessageApplication struct { - Id uint64 `json:",string"` - CoverImage string - Description string - Icon string - Name string + Id uint64 `json:"id,string"` + CoverImage *string `json:"cover_image,omitempty"` + Description string `json:"description"` + Icon *string `json:"icon,omitempty"` + Name string `json:"name"` } diff --git a/objects/channel/message/messagecall.go b/objects/channel/message/messagecall.go new file mode 100644 index 0000000..116bd79 --- /dev/null +++ b/objects/channel/message/messagecall.go @@ -0,0 +1,12 @@ +package message + +import ( + "time" + + "github.com/TicketsBot-cloud/gdl/utils" +) + +type MessageCall struct { + Participants utils.Uint64StringSlice `json:"participants"` + EndedTimestamp *time.Time `json:"ended_timestamp,omitempty"` +} diff --git a/objects/channel/message/messageinteraction.go b/objects/channel/message/messageinteraction.go new file mode 100644 index 0000000..3018156 --- /dev/null +++ b/objects/channel/message/messageinteraction.go @@ -0,0 +1,26 @@ +package message + +import ( + "github.com/TicketsBot-cloud/gdl/objects/member" + "github.com/TicketsBot-cloud/gdl/objects/user" +) + +// MessageInteraction is deprecated in favour of InteractionMetadata +type MessageInteraction struct { + Id uint64 `json:"id,string"` + Type int `json:"type"` + Name string `json:"name"` + User user.User `json:"user"` + Member *member.Member `json:"member,omitempty"` +} + +type MessageInteractionMetadata struct { + Id uint64 `json:"id,string"` + Type int `json:"type"` + User user.User `json:"user"` + AuthorizingIntegrationOwners map[string]string `json:"authorizing_integration_owners"` + OriginalResponseMessageId *uint64 `json:"original_response_message_id,string,omitempty"` + TargetUser *user.User `json:"target_user,omitempty"` + TargetMessageId *uint64 `json:"target_message_id,string,omitempty"` + InteractedMessageId *uint64 `json:"interacted_message_id,string,omitempty"` +} diff --git a/objects/channel/message/messagementioneduser.go b/objects/channel/message/messagementioneduser.go index 43c7b95..6af5d5d 100644 --- a/objects/channel/message/messagementioneduser.go +++ b/objects/channel/message/messagementioneduser.go @@ -8,5 +8,5 @@ import ( // Mentions is an array of users with partial member type MessageMentionedUser struct { user.User - Member member.Member + Member *member.Member `json:"member,omitempty"` } diff --git a/objects/channel/message/messagereference.go b/objects/channel/message/messagereference.go index 091323d..4d1b471 100644 --- a/objects/channel/message/messagereference.go +++ b/objects/channel/message/messagereference.go @@ -1,8 +1,9 @@ package message type MessageReference struct { - MessageId uint64 `json:"message_id,string"` - ChannelId uint64 `json:"channel_id,string"` - GuildId uint64 `json:"guild_id,string"` - FailIfNotExists bool `json:"fail_if_not_exists"` + Type *int `json:"type,omitempty"` + MessageId *uint64 `json:"message_id,string,omitempty"` + ChannelId *uint64 `json:"channel_id,string,omitempty"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + FailIfNotExists *bool `json:"fail_if_not_exists,omitempty"` } diff --git a/objects/channel/message/messagesnapshot.go b/objects/channel/message/messagesnapshot.go new file mode 100644 index 0000000..0226722 --- /dev/null +++ b/objects/channel/message/messagesnapshot.go @@ -0,0 +1,5 @@ +package message + +type MessageSnapshot struct { + Message Message `json:"message"` +} diff --git a/objects/channel/message/poll.go b/objects/channel/message/poll.go new file mode 100644 index 0000000..7aba905 --- /dev/null +++ b/objects/channel/message/poll.go @@ -0,0 +1,37 @@ +package message + +import ( + "time" + + "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" +) + +type Poll struct { + Question PollMedia `json:"question"` + Answers []PollAnswer `json:"answers"` + Expiry *time.Time `json:"expiry"` + AllowMultiselect bool `json:"allow_multiselect"` + LayoutType int `json:"layout_type"` + Results *PollResults `json:"results,omitempty"` +} + +type PollMedia struct { + Text *string `json:"text,omitempty"` + Emoji *emoji.Emoji `json:"emoji,omitempty"` +} + +type PollAnswer struct { + AnswerId int `json:"answer_id,omitempty"` + PollMedia PollMedia `json:"poll_media"` +} + +type PollResults struct { + IsFinalized bool `json:"is_finalized"` + AnswerCounts []PollAnswerCount `json:"answer_counts"` +} + +type PollAnswerCount struct { + Id int `json:"id"` + Count int `json:"count"` + MeVoted bool `json:"me_voted"` +} diff --git a/objects/channel/message/rolesubscriptiondata.go b/objects/channel/message/rolesubscriptiondata.go new file mode 100644 index 0000000..e8c444b --- /dev/null +++ b/objects/channel/message/rolesubscriptiondata.go @@ -0,0 +1,8 @@ +package message + +type RoleSubscriptionData struct { + RoleSubscriptionListingId uint64 `json:"role_subscription_listing_id,string"` + TierName string `json:"tier_name"` + TotalMonthsSubscribed int `json:"total_months_subscribed"` + IsRenewal bool `json:"is_renewal"` +} diff --git a/objects/channel/message/stickeritem.go b/objects/channel/message/stickeritem.go new file mode 100644 index 0000000..a48c9f8 --- /dev/null +++ b/objects/channel/message/stickeritem.go @@ -0,0 +1,9 @@ +package message + +import "github.com/TicketsBot-cloud/gdl/objects/guild/sticker" + +type StickerItem struct { + Id uint64 `json:"id,string"` + Name string `json:"name"` + FormatType sticker.StickerFormatType `json:"format_type"` +} From 2c8bfd4cd439c848bf475fc6f84402d0b3571813 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 21:07:21 +0100 Subject: [PATCH 10/73] Rename AllowedMentionType constants to verbose names Rename constants EVERYONE/USERS/ROLES to AllowedMentionTypeEveryone/AllowedMentionTypeUsers/AllowedMentionTypeRoles for clearer namespacing and to avoid global uppercase identifiers. Update the MentionEveryone helper to use the new constant. Changes in objects/channel/message/allowedmentiontype.go and objects/channel/message/allowedmention.go. https://docs.discord.com/developers/resources/message#allowed-mentions-object --- objects/channel/message/allowedmention.go | 2 +- objects/channel/message/allowedmentiontype.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/objects/channel/message/allowedmention.go b/objects/channel/message/allowedmention.go index c643a84..e97bf4c 100644 --- a/objects/channel/message/allowedmention.go +++ b/objects/channel/message/allowedmention.go @@ -11,5 +11,5 @@ type AllowedMention struct { // Helper var MentionEveryone = AllowedMention{ - Parse: []AllowedMentionType{EVERYONE}, + Parse: []AllowedMentionType{AllowedMentionTypeEveryone}, } diff --git a/objects/channel/message/allowedmentiontype.go b/objects/channel/message/allowedmentiontype.go index 74d0128..528e615 100644 --- a/objects/channel/message/allowedmentiontype.go +++ b/objects/channel/message/allowedmentiontype.go @@ -2,8 +2,8 @@ package message type AllowedMentionType string -const( - EVERYONE AllowedMentionType = "everyone" - USERS AllowedMentionType = "users" - ROLES AllowedMentionType = "roles" +const ( + AllowedMentionTypeRoles AllowedMentionType = "roles" + AllowedMentionTypeUsers AllowedMentionType = "users" + AllowedMentionTypeEveryone AllowedMentionType = "everyone" ) From a7e43617024d2b2771f01e6af62f5c083e195c92 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 21:13:40 +0100 Subject: [PATCH 11/73] Make embed fields optional and add type Add an optional Type field to Embed and mark several embed media fields as optional. Changes: add Type *string to Embed; add omitempty to ProxyUrl, Height and Width in EmbedImage and EmbedThumbnail; add ProxyUrl and set Url/Height/Width to omitempty in EmbedVideo; fix EmbedProvider json tag for Url and mark Name/Url as omitempty. These changes align struct JSON tags with optional Discord embed fields and prevent emitting zero-values. https://docs.discord.com/developers/resources/message#embed-object --- objects/channel/embed/embed.go | 1 + objects/channel/embed/embedimage.go | 6 +++--- objects/channel/embed/embedprovider.go | 4 ++-- objects/channel/embed/embedthumbnail.go | 6 +++--- objects/channel/embed/embedvideo.go | 7 ++++--- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/objects/channel/embed/embed.go b/objects/channel/embed/embed.go index 5f42336..11b4816 100644 --- a/objects/channel/embed/embed.go +++ b/objects/channel/embed/embed.go @@ -4,6 +4,7 @@ import "time" type Embed struct { Title string `json:"title,omitempty"` + Type *string `json:"type,omitempty"` Description string `json:"description,omitempty"` Url string `json:"url,omitempty"` Timestamp *time.Time `json:"timestamp,omitempty"` diff --git a/objects/channel/embed/embedimage.go b/objects/channel/embed/embedimage.go index 0c9b6a3..72ff2ea 100644 --- a/objects/channel/embed/embedimage.go +++ b/objects/channel/embed/embedimage.go @@ -2,7 +2,7 @@ package embed type EmbedImage struct { Url string `json:"url"` - ProxyUrl string `json:"proxy_url"` - Height int `json:"height"` - Width int `json:"width"` + ProxyUrl string `json:"proxy_url,omitempty"` + Height int `json:"height,omitempty"` + Width int `json:"width,omitempty"` } diff --git a/objects/channel/embed/embedprovider.go b/objects/channel/embed/embedprovider.go index 6e386ff..d42c0eb 100644 --- a/objects/channel/embed/embedprovider.go +++ b/objects/channel/embed/embedprovider.go @@ -1,6 +1,6 @@ package embed type EmbedProvider struct { - Name string `json:"name"` - Url string `json:"name"` + Name string `json:"name,omitempty"` + Url string `json:"url,omitempty"` } diff --git a/objects/channel/embed/embedthumbnail.go b/objects/channel/embed/embedthumbnail.go index bcb9c40..c487a24 100644 --- a/objects/channel/embed/embedthumbnail.go +++ b/objects/channel/embed/embedthumbnail.go @@ -2,7 +2,7 @@ package embed type EmbedThumbnail struct { Url string `json:"url"` - ProxyUrl string `json:"proxy_url"` - Height int `json:"height"` - Width int `json:"width"` + ProxyUrl string `json:"proxy_url,omitempty"` + Height int `json:"height,omitempty"` + Width int `json:"width,omitempty"` } diff --git a/objects/channel/embed/embedvideo.go b/objects/channel/embed/embedvideo.go index c67f805..973a544 100644 --- a/objects/channel/embed/embedvideo.go +++ b/objects/channel/embed/embedvideo.go @@ -1,7 +1,8 @@ package embed type EmbedVideo struct { - Url string `json:"url"` - Height int `json:"height"` - Width int `json:"width"` + Url string `json:"url,omitempty"` + ProxyUrl string `json:"proxy_url,omitempty"` + Height int `json:"height,omitempty"` + Width int `json:"width,omitempty"` } From 6c83721a37637c0e6fcefec5a50cd75c5a336af9 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 21:17:25 +0100 Subject: [PATCH 12/73] Expand Attachment struct with optional fields Update channel.Attachment to match extended API metadata: change Id tag to `id,string`, add optional fields (Title, Description, ContentType, Ephemeral, DurationSecs, Waveform, Flags) and make previously required fields nullable where appropriate (Height, Width now *int). Use omitempty on optional pointers to correctly handle absent values during JSON (un)marshalling. --- objects/channel/attachment.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/objects/channel/attachment.go b/objects/channel/attachment.go index 14aa849..cd1df56 100644 --- a/objects/channel/attachment.go +++ b/objects/channel/attachment.go @@ -1,11 +1,18 @@ package channel type Attachment struct { - Id uint64 `json:",string"` - Filename string `json:"filename"` - Size int `json:"size"` - Url string `json:"url"` - ProxyUrl string `json:"proxy_url"` - Height int `json:"height"` - Width int `json:"width"` + Id uint64 `json:"id,string"` + Filename string `json:"filename"` + Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` + ContentType *string `json:"content_type,omitempty"` + Size int `json:"size"` + Url string `json:"url"` + ProxyUrl string `json:"proxy_url"` + Height *int `json:"height,omitempty"` + Width *int `json:"width,omitempty"` + Ephemeral *bool `json:"ephemeral,omitempty"` + DurationSecs *float64 `json:"duration_secs,omitempty"` + Waveform *string `json:"waveform,omitempty"` + Flags *int `json:"flags,omitempty"` } From c7ec928071996cef1b1724261573995ec7bced10 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 21:35:16 +0100 Subject: [PATCH 13/73] Make channel fields optional, handle nil GuildId Convert many Channel/CachedChannel fields to pointer/omitempty types to support partial/optional channel payloads (name, topic, position, icon, owner/application IDs, timestamps, thread fields, forum tags, etc.). Update Channel<->CachedChannel conversions accordingly. Harden cache and DB code (bolt, memory, pg) to guard against nil GuildId by extracting a zero-value guildId before marshaling/inserting and checking for nil when updating guild maps to avoid nil dereferences. Add ForumTag and DefaultReaction types for forum support. These changes enable safer handling of partial channel objects and prevent panics when GuildId is absent. https://docs.discord.com/developers/resources/channel --- cache/boltcache.go | 6 ++- cache/memorycache.go | 24 ++++++----- cache/pgcache.go | 27 ++++++++++--- objects/channel/cachedchannel.go | 17 ++++---- objects/channel/channel.go | 69 ++++++++++++++++++++------------ objects/channel/forumtag.go | 14 +++++++ 6 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 objects/channel/forumtag.go diff --git a/cache/boltcache.go b/cache/boltcache.go index 387dcc7..32d3c76 100644 --- a/cache/boltcache.go +++ b/cache/boltcache.go @@ -380,9 +380,13 @@ func (c *BoltCache) StoreChannels(channels []channel.Channel) { b := tx.Bucket([]byte("channels")) for _, ch := range channels { + var guildId uint64 + if ch.GuildId != nil { + guildId = *ch.GuildId + } cwg := channelWithGuild{ CachedChannel: ch.ToCachedChannel(), - guildId: ch.GuildId, + guildId: guildId, } if encoded, err := json.Marshal(cwg); err == nil { diff --git a/cache/memorycache.go b/cache/memorycache.go index b75228d..d2f7fa8 100644 --- a/cache/memorycache.go +++ b/cache/memorycache.go @@ -300,19 +300,21 @@ func (c *MemoryCache) StoreChannels(ctx context.Context, channels []channel.Chan // Add to guild object c.guildLock.Lock() - if guild, found := c.guilds[channel.GuildId]; found { - // Check to see if channel already exists - var channelExists bool - for _, userId := range guild.Channels { - if userId == channel.Id { - channelExists = true - break + if channel.GuildId != nil { + if guild, found := c.guilds[*channel.GuildId]; found { + // Check to see if channel already exists + var channelExists bool + for _, userId := range guild.Channels { + if userId == channel.Id { + channelExists = true + break + } } - } - if !channelExists { - guild.Channels = append(guild.Channels, channel.Id) - c.guilds[channel.GuildId] = guild + if !channelExists { + guild.Channels = append(guild.Channels, channel.Id) + c.guilds[*channel.GuildId] = guild + } } } c.guildLock.Unlock() diff --git a/cache/pgcache.go b/cache/pgcache.go index 4fa9c89..7539b18 100644 --- a/cache/pgcache.go +++ b/cache/pgcache.go @@ -255,7 +255,11 @@ func (c *PgCache) StoreGuilds(ctx context.Context, guilds []guild.Guild) error { return err } - batch.Queue(`INSERT INTO channels("channel_id", "guild_id", "data") VALUES($1, $2, $3) ON CONFLICT("channel_id") DO UPDATE SET "data" = $3;`, channel.Id, channel.GuildId, string(encoded)) + var chGuildId uint64 + if channel.GuildId != nil { + chGuildId = *channel.GuildId + } + batch.Queue(`INSERT INTO channels("channel_id", "guild_id", "data") VALUES($1, $2, $3) ON CONFLICT("channel_id") DO UPDATE SET "data" = $3;`, channel.Id, chGuildId, string(encoded)) } } @@ -316,7 +320,8 @@ func (c *PgCache) StoreGuild(ctx context.Context, g guild.Guild) error { } for i, channel := range g.Channels { - channel.GuildId = g.Id + gId := g.Id + channel.GuildId = &gId g.Channels[i] = channel } @@ -615,7 +620,11 @@ func (c *PgCache) StoreChannel(ctx context.Context, ch channel.Channel) error { return err } - _, err = c.Exec(ctx, queryInsertChannel, ch.Id, ch.GuildId, string(encoded)) + var guildId uint64 + if ch.GuildId != nil { + guildId = *ch.GuildId + } + _, err = c.Exec(ctx, queryInsertChannel, ch.Id, guildId, string(encoded)) return err } @@ -632,7 +641,11 @@ func (c *PgCache) StoreChannels(ctx context.Context, channels []channel.Channel) return err } - batch.Queue(queryInsertChannel, ch.Id, ch.GuildId, string(encoded)) + var chGuildId uint64 + if ch.GuildId != nil { + chGuildId = *ch.GuildId + } + batch.Queue(queryInsertChannel, ch.Id, chGuildId, string(encoded)) } br := c.SendBatch(ctx, batch) @@ -664,7 +677,11 @@ func (c *PgCache) ReplaceChannels(ctx context.Context, guildId uint64, channels return err } - if _, err := tx.Exec(ctx, queryInsertChannel, ch.Id, ch.GuildId, string(encoded)); err != nil { + var txGuildId uint64 + if ch.GuildId != nil { + txGuildId = *ch.GuildId + } + if _, err := tx.Exec(ctx, queryInsertChannel, ch.Id, txGuildId, string(encoded)); err != nil { return err } } diff --git a/objects/channel/cachedchannel.go b/objects/channel/cachedchannel.go index d8d3022..f540b21 100644 --- a/objects/channel/cachedchannel.go +++ b/objects/channel/cachedchannel.go @@ -9,27 +9,27 @@ import ( type CachedChannel struct { GuildId uint64 `json:"-"` Type ChannelType `json:"type"` - Position int `json:"position"` + Position *int `json:"position,omitempty"` PermissionOverwrites []PermissionOverwrite `json:"permission_overwrites"` - Name string `json:"name"` - Topic string `json:"topic"` + Name *string `json:"name,omitempty"` + Topic *string `json:"topic,omitempty"` Nsfw bool `json:"nsfw"` LastMessageId objects.NullableSnowflake `json:"last_message_id"` Bitrate int `json:"bitrate"` UserLimit int `json:"user_limit"` RateLimitPerUser int `json:"rate_limit_per_user"` - Icon string `json:"icon"` - OwnerId uint64 `json:"owner_id,string"` - ApplicationId uint64 `json:"application_id"` + Icon *string `json:"icon,omitempty"` + OwnerId *uint64 `json:"owner_id,string,omitempty"` + ApplicationId *uint64 `json:"application_id,string,omitempty"` ParentId objects.NullableSnowflake `json:"parent_id,omitempty"` - LastPinTimestamp time.Time `json:"last_pin_timestamp"` + LastPinTimestamp *time.Time `json:"last_pin_timestamp,omitempty"` } func (c *CachedChannel) ToChannel(channelId, guildId uint64) Channel { return Channel{ Id: channelId, Type: c.Type, - GuildId: guildId, + GuildId: &guildId, Position: c.Position, PermissionOverwrites: c.PermissionOverwrites, Name: c.Name, @@ -39,7 +39,6 @@ func (c *CachedChannel) ToChannel(channelId, guildId uint64) Channel { Bitrate: c.Bitrate, UserLimit: c.UserLimit, RateLimitPerUser: c.RateLimitPerUser, - Recipients: nil, Icon: c.Icon, OwnerId: c.OwnerId, ApplicationId: c.ApplicationId, diff --git a/objects/channel/channel.go b/objects/channel/channel.go index 961cdc0..e08387e 100644 --- a/objects/channel/channel.go +++ b/objects/channel/channel.go @@ -5,34 +5,46 @@ import ( "time" "github.com/TicketsBot-cloud/gdl/objects" + "github.com/TicketsBot-cloud/gdl/utils" "github.com/TicketsBot-cloud/gdl/objects/user" ) type Channel struct { - Id uint64 `json:"id,string"` - Type ChannelType `json:"type"` - GuildId uint64 `json:"guild_id,string"` - Position int `json:"position"` - PermissionOverwrites []PermissionOverwrite `json:"permission_overwrites"` - Name string `json:"name"` - Topic string `json:"topic"` - Nsfw bool `json:"nsfw"` - LastMessageId objects.NullableSnowflake `json:"last_message_id"` - Bitrate int `json:"bitrate"` - UserLimit int `json:"user_limit"` - RateLimitPerUser int `json:"rate_limit_per_user"` - Recipients []user.User `json:"recipients"` - Icon string `json:"icon"` - OwnerId uint64 `json:"owner_id,string"` // Owner of a group DM - ApplicationId uint64 `json:"application_id,string"` - ParentId objects.NullableSnowflake `json:"parent_id,omitempty"` - LastPinTimestamp time.Time `json:"last_pin_timestamp"` - RtcRegion *string `json:"rtc_region"` - VideoQualityMode VideoQualityMode `json:"video_quality_mode"` - MessageCount uint64 `json:"message_count"` - MemberCount uint64 `json:"member_count"` - ThreadMetadata *ThreadMetadata `json:"thread_metadata,omitempty"` - Member ThreadMember `json:"member"` + Id uint64 `json:"id,string"` + Type ChannelType `json:"type"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + Position *int `json:"position,omitempty"` + PermissionOverwrites []PermissionOverwrite `json:"permission_overwrites,omitempty"` + Name *string `json:"name,omitempty"` + Topic *string `json:"topic,omitempty"` + Nsfw bool `json:"nsfw,omitempty"` + LastMessageId objects.NullableSnowflake `json:"last_message_id"` + Bitrate int `json:"bitrate,omitempty"` + UserLimit int `json:"user_limit,omitempty"` + RateLimitPerUser int `json:"rate_limit_per_user,omitempty"` + Recipients []user.User `json:"recipients,omitempty"` + Icon *string `json:"icon,omitempty"` + OwnerId *uint64 `json:"owner_id,string,omitempty"` + ApplicationId *uint64 `json:"application_id,string,omitempty"` + Managed *bool `json:"managed,omitempty"` + ParentId objects.NullableSnowflake `json:"parent_id,omitempty"` + LastPinTimestamp *time.Time `json:"last_pin_timestamp,omitempty"` + RtcRegion *string `json:"rtc_region,omitempty"` + VideoQualityMode VideoQualityMode `json:"video_quality_mode,omitempty"` + MessageCount int `json:"message_count,omitempty"` + MemberCount int `json:"member_count,omitempty"` + ThreadMetadata *ThreadMetadata `json:"thread_metadata,omitempty"` + Member *ThreadMember `json:"member,omitempty"` + DefaultAutoArchiveDuration *int `json:"default_auto_archive_duration,omitempty"` + Permissions *string `json:"permissions,omitempty"` + Flags *int `json:"flags,omitempty"` + TotalMessageSent *int `json:"total_message_sent,omitempty"` + AvailableTags []ForumTag `json:"available_tags,omitempty"` + AppliedTags utils.Uint64StringSlice `json:"applied_tags,omitempty"` + DefaultReactionEmoji *DefaultReaction `json:"default_reaction_emoji,omitempty"` + DefaultThreadRateLimitPerUser *int `json:"default_thread_rate_limit_per_user,omitempty"` + DefaultSortOrder *int `json:"default_sort_order,omitempty"` + DefaultForumLayout *int `json:"default_forum_layout,omitempty"` } func (c *Channel) Mention() string { @@ -40,8 +52,13 @@ func (c *Channel) Mention() string { } func (c *Channel) ToCachedChannel() CachedChannel { + var guildId uint64 + if c.GuildId != nil { + guildId = *c.GuildId + } + return CachedChannel{ - GuildId: c.GuildId, + GuildId: guildId, Type: c.Type, Position: c.Position, PermissionOverwrites: c.PermissionOverwrites, @@ -64,6 +81,6 @@ func (c *Channel) ToPartialChannel() PartialChannel { return PartialChannel{ Id: c.Id, Type: c.Type, - Name: &c.Name, + Name: c.Name, } } diff --git a/objects/channel/forumtag.go b/objects/channel/forumtag.go new file mode 100644 index 0000000..2186f60 --- /dev/null +++ b/objects/channel/forumtag.go @@ -0,0 +1,14 @@ +package channel + +type ForumTag struct { + Id uint64 `json:"id,string"` + Name string `json:"name"` + Moderated bool `json:"moderated"` + EmojiId *uint64 `json:"emoji_id,string,omitempty"` + EmojiName *string `json:"emoji_name,omitempty"` +} + +type DefaultReaction struct { + EmojiId *uint64 `json:"emoji_id,string,omitempty"` + EmojiName *string `json:"emoji_name,omitempty"` +} From 3e56cf5d6fb43fe492b4f6191556cb6ae37e07f7 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 21:39:25 +0100 Subject: [PATCH 14/73] Always include PermissionOverwrite.Id in JSON Remove `omitempty` from the Id json tag so the Id field is always serialized (as a string). This ensures PermissionOverwrite objects include the id in outgoing JSON, preventing the field from being omitted during marshaling and aligning with expected API behavior. https://docs.discord.com/developers/topics/permissions#permission-overwrites --- objects/channel/permissionoverwrite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objects/channel/permissionoverwrite.go b/objects/channel/permissionoverwrite.go index 41dc7ba..be80778 100644 --- a/objects/channel/permissionoverwrite.go +++ b/objects/channel/permissionoverwrite.go @@ -1,7 +1,7 @@ package channel type PermissionOverwrite struct { - Id uint64 `json:"id,string,omitempty"` + Id uint64 `json:"id,string"` Type PermissionOverwriteType `json:"type"` Allow uint64 `json:"allow,string"` Deny uint64 `json:"deny,string"` From cc2f0cb8e8d9058515047d86c46d97c5828f0e6e Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 21:54:20 +0100 Subject: [PATCH 15/73] Refactor automoderation types & metadata Add KeywordPresetType and corresponding constants, and change TriggerMetadata.Presets to []KeywordPresetType for clearer preset semantics. Make ActionMetadata.ChannelId and DurationSeconds pointer fields with `omitempty` to represent optional JSON values. Replace Rule.ExemptRoles and ExemptChannels with utils.Uint64StringSlice to standardize uint64-from-string handling. Add import for utils and apply minor formatting/type cleanups. https://docs.discord.com/developers/resources/auto-moderation --- objects/automoderation/automoderation.go | 56 ++++++++++++++---------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/objects/automoderation/automoderation.go b/objects/automoderation/automoderation.go index b4d5a95..7b54a17 100644 --- a/objects/automoderation/automoderation.go +++ b/objects/automoderation/automoderation.go @@ -1,5 +1,7 @@ package automoderation +import "github.com/TicketsBot-cloud/gdl/utils" + type EventType int const ( @@ -17,27 +19,35 @@ const ( TriggerTypeMemberProfile TriggerType = 6 ) +type KeywordPresetType int + +const ( + KeywordPresetTypeProfanity KeywordPresetType = 1 + KeywordPresetTypeSexualContent KeywordPresetType = 2 + KeywordPresetTypeSlurs KeywordPresetType = 3 +) + type ActionType int const ( - ActionTypeBlockMessage ActionType = 1 - ActionTypeSendAlertMessage ActionType = 2 - ActionTypeTimeout ActionType = 3 - ActionTypeBlockMemberInteraction ActionType = 4 + ActionTypeBlockMessage ActionType = 1 + ActionTypeSendAlertMessage ActionType = 2 + ActionTypeTimeout ActionType = 3 + ActionTypeBlockMemberInteraction ActionType = 4 ) type TriggerMetadata struct { - KeywordFilter []string `json:"keyword_filter"` - RegexPatterns []string `json:"regex_patterns"` - Presets []int `json:"presets"` - AllowList []string `json:"allow_list"` - MentionTotalLimit int `json:"mention_total_limit"` - MentionRaidProtectionEnabled bool `json:"mention_raid_protection_enabled"` + KeywordFilter []string `json:"keyword_filter"` + RegexPatterns []string `json:"regex_patterns"` + Presets []KeywordPresetType `json:"presets"` + AllowList []string `json:"allow_list"` + MentionTotalLimit int `json:"mention_total_limit"` + MentionRaidProtectionEnabled bool `json:"mention_raid_protection_enabled"` } type ActionMetadata struct { - ChannelId uint64 `json:"channel_id,string"` - DurationSeconds int `json:"duration_seconds"` + ChannelId *uint64 `json:"channel_id,string,omitempty"` + DurationSeconds *int `json:"duration_seconds,omitempty"` CustomMessage *string `json:"custom_message,omitempty"` } @@ -47,15 +57,15 @@ type Action struct { } type Rule struct { - Id uint64 `json:"id,string"` - GuildId uint64 `json:"guild_id,string"` - Name string `json:"name"` - CreatorId uint64 `json:"creator_id,string"` - EventType EventType `json:"event_type"` - TriggerType TriggerType `json:"trigger_type"` - TriggerMetadata TriggerMetadata `json:"trigger_metadata"` - Actions []Action `json:"actions"` - Enabled bool `json:"enabled"` - ExemptRoles []uint64 `json:"exempt_roles"` - ExemptChannels []uint64 `json:"exempt_channels"` + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + Name string `json:"name"` + CreatorId uint64 `json:"creator_id,string"` + EventType EventType `json:"event_type"` + TriggerType TriggerType `json:"trigger_type"` + TriggerMetadata TriggerMetadata `json:"trigger_metadata"` + Actions []Action `json:"actions"` + Enabled bool `json:"enabled"` + ExemptRoles utils.Uint64StringSlice `json:"exempt_roles"` + ExemptChannels utils.Uint64StringSlice `json:"exempt_channels"` } From cb9cd14edd90248f5dfcbe39d3ff5b9c3c37e863 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 22:00:57 +0100 Subject: [PATCH 16/73] Prefix entitlement constants with EntitlementType Rename EntitlementType constants in objects/entitlement/entitlement.go to include the 'EntitlementType' prefix (e.g. TypePurchase -> EntitlementTypePurchase) for improved clarity and to avoid potential name collisions. Underlying constant values are unchanged. https://docs.discord.com/developers/resources/entitlement#entitlement-resource --- objects/entitlement/entitlement.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/objects/entitlement/entitlement.go b/objects/entitlement/entitlement.go index 1b889ba..c56b300 100644 --- a/objects/entitlement/entitlement.go +++ b/objects/entitlement/entitlement.go @@ -18,12 +18,12 @@ type Entitlement struct { type EntitlementType uint16 const ( - TypePurchase EntitlementType = iota + 1 - TypePremiumSubscription - TypeDeveloperGift - TypeTestModePurchase - TypeFreePurchase - TypeUserGift - TypePremiumPurchase - TypeApplicationSubscription + EntitlementTypePurchase EntitlementType = iota + 1 + EntitlementTypePremiumSubscription + EntitlementTypeDeveloperGift + EntitlementTypeTestModePurchase + EntitlementTypeFreePurchase + EntitlementTypeUserGift + EntitlementTypePremiumPurchase + EntitlementTypeApplicationSubscription ) From 18e798f59a264451efea894523d8775d72a36f6c Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 22:06:30 +0100 Subject: [PATCH 17/73] Make Emoji fields nullable/optional Change Emoji and CachedEmoji to use pointer types and omitempty tags for optional Discord fields. Name is now *string in both structs; Emoji.User is now *user.User; boolean flags and roles are marked omitempty and an Available *bool was added. Update conversion helpers: CachedEmoji.ToEmoji now accepts a user value pointer and Emoji.ToCachedEmoji safely handles nil User when extracting the user ID. These changes allow representing absent/custom emoji data and avoid zero-value ambiguity when encoding/decoding API payloads. https://docs.discord.com/developers/resources/emoji#emoji-resource --- objects/guild/emoji/cachedemoji.go | 6 +++--- objects/guild/emoji/emoji.go | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/objects/guild/emoji/cachedemoji.go b/objects/guild/emoji/cachedemoji.go index 05ef8ba..b045d6b 100644 --- a/objects/guild/emoji/cachedemoji.go +++ b/objects/guild/emoji/cachedemoji.go @@ -7,7 +7,7 @@ import ( type CachedEmoji struct { GuildId uint64 `json:"-"` - Name string `json:"name"` + Name *string `json:"name,omitempty"` Roles []uint64 `json:"roles"` User uint64 `json:"user"` RequireColons bool `json:"require_colons"` @@ -15,12 +15,12 @@ type CachedEmoji struct { Animated bool `json:"animated"` } -func (e *CachedEmoji) ToEmoji(emojiId uint64, user user.User) Emoji { +func (e *CachedEmoji) ToEmoji(emojiId uint64, u user.User) Emoji { return Emoji{ Id: objects.NewNullableSnowflake(emojiId), Name: e.Name, Roles: e.Roles, - User: user, + User: &u, RequireColons: e.RequireColons, Managed: e.Managed, Animated: e.Animated, diff --git a/objects/guild/emoji/emoji.go b/objects/guild/emoji/emoji.go index 5ab94a0..e4cb553 100644 --- a/objects/guild/emoji/emoji.go +++ b/objects/guild/emoji/emoji.go @@ -9,20 +9,26 @@ import ( // https://discord.com/developers/docs/resources/emoji#emoji-object type Emoji struct { Id objects.NullableSnowflake `json:"id"` - Name string `json:"name"` // if this is not a custom emote, Name will be the unicode emoji, and Id will be 0 + Name *string `json:"name,omitempty"` // null when custom emoji data is not available; unicode emoji string for standard emoji Roles utils.Uint64StringSlice `json:"roles,omitempty"` - User user.User `json:"user"` - RequireColons bool `json:"require_colons"` - Managed bool `json:"managed"` - Animated bool `json:"animated"` + User *user.User `json:"user,omitempty"` + RequireColons bool `json:"require_colons,omitempty"` + Managed bool `json:"managed,omitempty"` + Animated bool `json:"animated,omitempty"` + Available *bool `json:"available,omitempty"` } func (e *Emoji) ToCachedEmoji(guildId uint64) CachedEmoji { + var userId uint64 + if e.User != nil { + userId = e.User.Id + } + return CachedEmoji{ GuildId: guildId, Name: e.Name, Roles: e.Roles, - User: e.User.Id, + User: userId, RequireColons: e.RequireColons, Managed: e.Managed, Animated: e.Animated, From 2f1891e9a164c7a49701f91e4fa2bea15fcd1595 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 22:16:27 +0100 Subject: [PATCH 18/73] Add recurrence rule support to events Introduce recurrence types and RecurrenceRule to represent repeating scheduled events (frequency, interval, by-weekday/month/day, count, start/end, etc.). Add RecurrenceNWeekday to support nth-weekday rules. Include a RecurrenceRule pointer on GuildScheduledEvent and update JSON tags for optional pointer ID fields (channel_id, creator_id, entity_id) to use omitempty so empty values are omitted during marshaling. https://docs.discord.com/developers/resources/guild-scheduled-event#guild-scheduled-event --- .../guild/scheduledevent/scheduledevent.go | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/objects/guild/scheduledevent/scheduledevent.go b/objects/guild/scheduledevent/scheduledevent.go index 42c8f27..c3d05e6 100644 --- a/objects/guild/scheduledevent/scheduledevent.go +++ b/objects/guild/scheduledevent/scheduledevent.go @@ -29,6 +29,62 @@ const ( StatusCanceled ) +type RecurrenceFrequency int + +const ( + RecurrenceFrequencyYearly RecurrenceFrequency = iota + RecurrenceFrequencyMonthly + RecurrenceFrequencyWeekly + RecurrenceFrequencyDaily +) + +type RecurrenceWeekday int + +const ( + RecurrenceWeekdayMonday RecurrenceWeekday = iota + RecurrenceWeekdayTuesday + RecurrenceWeekdayWednesday + RecurrenceWeekdayThursday + RecurrenceWeekdayFriday + RecurrenceWeekdaySaturday + RecurrenceWeekdaySunday +) + +type RecurrenceMonth int + +const ( + RecurrenceMonthJanuary RecurrenceMonth = iota + 1 + RecurrenceMonthFebruary + RecurrenceMonthMarch + RecurrenceMonthApril + RecurrenceMonthMay + RecurrenceMonthJune + RecurrenceMonthJuly + RecurrenceMonthAugust + RecurrenceMonthSeptember + RecurrenceMonthOctober + RecurrenceMonthNovember + RecurrenceMonthDecember +) + +type RecurrenceNWeekday struct { + N int `json:"n"` + Day RecurrenceWeekday `json:"day"` +} + +type RecurrenceRule struct { + Start time.Time `json:"start"` + End *time.Time `json:"end,omitempty"` + Frequency RecurrenceFrequency `json:"frequency"` + Interval int `json:"interval"` + ByWeekday []RecurrenceWeekday `json:"by_weekday,omitempty"` + ByNWeekday []RecurrenceNWeekday `json:"by_n_weekday,omitempty"` + ByMonth []RecurrenceMonth `json:"by_month,omitempty"` + ByMonthDay []int `json:"by_month_day,omitempty"` + ByYearDay []int `json:"by_year_day,omitempty"` + Count *int `json:"count,omitempty"` +} + type EntityMetadata struct { Location *string `json:"location,omitempty"` } @@ -36,8 +92,8 @@ type EntityMetadata struct { type GuildScheduledEvent struct { Id uint64 `json:"id,string"` GuildId uint64 `json:"guild_id,string"` - ChannelId *uint64 `json:"channel_id,string"` - CreatorId *uint64 `json:"creator_id,string"` + ChannelId *uint64 `json:"channel_id,string,omitempty"` + CreatorId *uint64 `json:"creator_id,string,omitempty"` Name string `json:"name"` Description *string `json:"description,omitempty"` ScheduledStartTime time.Time `json:"scheduled_start_time"` @@ -45,9 +101,10 @@ type GuildScheduledEvent struct { PrivacyLevel PrivacyLevel `json:"privacy_level"` Status Status `json:"status"` EntityType EntityType `json:"entity_type"` - EntityId *uint64 `json:"entity_id,string"` + EntityId *uint64 `json:"entity_id,string,omitempty"` EntityMetadata *EntityMetadata `json:"entity_metadata,omitempty"` Creator *user.User `json:"creator,omitempty"` UserCount *int `json:"user_count,omitempty"` Image *string `json:"image,omitempty"` + RecurrenceRule *RecurrenceRule `json:"recurrence_rule,omitempty"` } From 339100dd0ea099722025fbf2824c56e00ba3a142 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 22:19:31 +0100 Subject: [PATCH 19/73] Add omitempty to Sticker JSON tags Mark optional Sticker struct fields with `omitempty` in their JSON tags (PackId, Description, Available, GuildId, User, SortValue) so empty or nil values are omitted when marshaling. This prevents null/zero fields from being serialized for optional sticker data. https://docs.discord.com/developers/resources/sticker#sticker-resource --- objects/guild/sticker/sticker.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/objects/guild/sticker/sticker.go b/objects/guild/sticker/sticker.go index da0ff3a..47129d2 100644 --- a/objects/guild/sticker/sticker.go +++ b/objects/guild/sticker/sticker.go @@ -20,14 +20,14 @@ const ( type Sticker struct { Id uint64 `json:"id,string"` - PackId *uint64 `json:"pack_id,string"` + PackId *uint64 `json:"pack_id,string,omitempty"` Name string `json:"name"` - Description *string `json:"description"` + Description *string `json:"description,omitempty"` Tags string `json:"tags"` Type StickerType `json:"type"` FormatType StickerFormatType `json:"format_type"` - Available *bool `json:"available"` - GuildId *uint64 `json:"guild_id,string"` - User *user.User `json:"user"` - SortValue *int `json:"sort_value"` + Available *bool `json:"available,omitempty"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + User *user.User `json:"user,omitempty"` + SortValue *int `json:"sort_value,omitempty"` } From b1a5401479852ef6da9c15d536fe2681bad2dd65 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 23:44:05 +0100 Subject: [PATCH 20/73] Make guild/integration fields optional; add stickers Convert many guild and integration struct fields to pointer types with `omitempty` to correctly represent optional/absent values from the API. Add support for stickers (import and fields in Guild, GuildPreview), introduce IncidentsData and IntegrationApplication structs, and expand RoleTags with new tag fields. Adjust related types and logic: Ban.Reason, Guild.IconUrl (handle nullable icon), GuildWidget.InstantInvite, GuildEmbed.ChannelId (NullableSnowflake), WelcomeScreen.Description, CachedGuild field nullability and ToGuild mapping for WidgetEnabled. These changes align the models with updated Discord API responses and optional fields. https://docs.discord.com/developers/resources/guild --- objects/guild/ban.go | 2 +- objects/guild/cachedguild.go | 28 +++++------ objects/guild/guild.go | 73 +++++++++++++++++------------ objects/guild/guildembed.go | 7 ++- objects/guild/guildpreview.go | 26 +++++----- objects/guild/guildwidget.go | 2 +- objects/guild/role.go | 9 +++- objects/guild/welcomescreen.go | 2 +- objects/integration/integrations.go | 36 +++++++++----- 9 files changed, 112 insertions(+), 73 deletions(-) diff --git a/objects/guild/ban.go b/objects/guild/ban.go index b9cd06f..5088d1d 100644 --- a/objects/guild/ban.go +++ b/objects/guild/ban.go @@ -5,6 +5,6 @@ import ( ) type Ban struct { - Reason string `json:"reason,omitempty"` + Reason *string `json:"reason"` User user.User `json:"user"` } diff --git a/objects/guild/cachedguild.go b/objects/guild/cachedguild.go index e5450e0..780d81b 100644 --- a/objects/guild/cachedguild.go +++ b/objects/guild/cachedguild.go @@ -9,12 +9,12 @@ import ( type CachedGuild struct { Id uint64 `json:"id"` Name string `json:"name"` - Icon string `json:"icon"` - Splash string `json:"splash"` + Icon *string `json:"icon"` + Splash *string `json:"splash"` Owner bool `json:"owner"` OwnerId uint64 `json:"owner_id"` Permissions uint64 `json:"permissions"` - Region string `json:"region"` + Region *string `json:"region,omitempty"` AfkChannelId objects.NullableSnowflake `json:"afk_channel_id"` AfkTimeout int `json:"afk_timeout"` VerificationLevel int `json:"verification_level"` @@ -25,27 +25,27 @@ type CachedGuild struct { Features []GuildFeature `json:"features"` MfaLevel int `json:"mfa_level"` ApplicationId objects.NullableSnowflake `json:"application_id"` - WidgetEnabled bool `json:"widget_enabled"` - WidgetChannelId objects.NullableSnowflake `json:"widget_channel_id"` + WidgetEnabled *bool `json:"widget_enabled,omitempty"` + WidgetChannelId objects.NullableSnowflake `json:"widget_channel_id,omitempty"` SystemChannelId objects.NullableSnowflake `json:"system_channel_id"` SystemChannelFlags uint16 `json:"system_channel_flags"` RulesChannelId objects.NullableSnowflake `json:"rules_channel_id,omitempty"` JoinedAt time.Time `json:"joined_at"` Large bool `json:"large"` - Unavailable *bool `json:"unavailable"` + Unavailable *bool `json:"unavailable,omitempty"` MemberCount int `json:"member_count"` Channels []uint64 `json:"-"` Presences []uint64 `json:"-"` - MaxPresences int `json:"max_presences"` - MaxMembers int `json:"max_members"` - VanityUrlCode string `json:"vanity_url_code"` - Description string `json:"description"` - Banner string `json:"banner"` + MaxPresences *int `json:"max_presences,omitempty"` + MaxMembers *int `json:"max_members,omitempty"` + VanityUrlCode *string `json:"vanity_url_code"` + Description *string `json:"description"` + Banner *string `json:"banner"` PremiumTier PremiumTier `json:"premium_tier"` - PremiumSubscriptionCount int `json:"premium_subscription_count"` + PremiumSubscriptionCount *int `json:"premium_subscription_count,omitempty"` PreferredLocale string `json:"preferred_locale"` PublicUpdatesChannelId objects.NullableSnowflake `json:"public_updates_channel_id"` - MaxVideoChannelUsers int `json:"max_video_channel_users"` + MaxVideoChannelUsers *int `json:"max_video_channel_users,omitempty"` } func (g *CachedGuild) ToGuild(guildId uint64) Guild { @@ -66,7 +66,7 @@ func (g *CachedGuild) ToGuild(guildId uint64) Guild { Features: g.Features, MfaLevel: g.MfaLevel, ApplicationId: g.ApplicationId, - WidgetEnabled: bool(g.WidgetEnabled), + WidgetEnabled: g.WidgetEnabled, WidgetChannelId: g.WidgetChannelId, SystemChannelId: g.SystemChannelId, SystemChannelFlags: g.SystemChannelFlags, diff --git a/objects/guild/guild.go b/objects/guild/guild.go index a3affdd..8f0337c 100644 --- a/objects/guild/guild.go +++ b/objects/guild/guild.go @@ -8,20 +8,25 @@ import ( "github.com/TicketsBot-cloud/gdl/objects" "github.com/TicketsBot-cloud/gdl/objects/channel" "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" + "github.com/TicketsBot-cloud/gdl/objects/guild/sticker" "github.com/TicketsBot-cloud/gdl/objects/member" ) type Guild struct { Id uint64 `json:"id,string"` Name string `json:"name"` - Icon string `json:"icon"` - Splash string `json:"splash"` - Owner bool `json:"owner"` + Icon *string `json:"icon"` + IconHash *string `json:"icon_hash,omitempty"` + Splash *string `json:"splash"` + DiscoverySplash *string `json:"discovery_splash"` + Owner bool `json:"owner,omitempty"` OwnerId uint64 `json:"owner_id,string"` - Permissions uint64 `json:"permissions,string"` - Region string `json:"region"` + Permissions uint64 `json:"permissions,string,omitempty"` + Region *string `json:"region,omitempty"` AfkChannelId objects.NullableSnowflake `json:"afk_channel_id"` AfkTimeout int `json:"afk_timeout"` + WidgetEnabled *bool `json:"widget_enabled,omitempty"` + WidgetChannelId objects.NullableSnowflake `json:"widget_channel_id,omitempty"` VerificationLevel int `json:"verification_level"` DefaultMessageNotifications int `json:"default_message_notifications"` ExplicitContentFilter int `json:"explicit_content_filter"` @@ -30,46 +35,56 @@ type Guild struct { Features []GuildFeature `json:"features"` MfaLevel int `json:"mfa_level"` ApplicationId objects.NullableSnowflake `json:"application_id"` - WidgetEnabled bool `json:"widget_enabled"` - WidgetChannelId objects.NullableSnowflake `json:"widget_channel_id"` SystemChannelId objects.NullableSnowflake `json:"system_channel_id"` SystemChannelFlags uint16 `json:"system_channel_flags"` RulesChannelId objects.NullableSnowflake `json:"rules_channel_id,omitempty"` - JoinedAt time.Time `json:"joined_at"` - Large bool `json:"large"` - Unavailable *bool `json:"unavailable"` - MemberCount int `json:"member_count"` - VoiceStates []VoiceState `json:"voice_states"` - Members []member.Member `json:"members"` - Channels []channel.Channel `json:"channels"` - Threads []channel.Channel `json:"threads"` - MaxPresences int `json:"max_presences"` - MaxMembers int `json:"max_members"` - VanityUrlCode string `json:"vanity_url_code"` - Description string `json:"description"` - Banner string `json:"banner"` + JoinedAt time.Time `json:"joined_at,omitempty"` + Large bool `json:"large,omitempty"` + Unavailable *bool `json:"unavailable,omitempty"` + MemberCount int `json:"member_count,omitempty"` + VoiceStates []VoiceState `json:"voice_states,omitempty"` + Members []member.Member `json:"members,omitempty"` + Channels []channel.Channel `json:"channels,omitempty"` + Threads []channel.Channel `json:"threads,omitempty"` + MaxPresences *int `json:"max_presences,omitempty"` + MaxMembers *int `json:"max_members,omitempty"` + VanityUrlCode *string `json:"vanity_url_code"` + Description *string `json:"description"` + Banner *string `json:"banner"` PremiumTier PremiumTier `json:"premium_tier"` - PremiumSubscriptionCount int `json:"premium_subscription_count"` + PremiumSubscriptionCount *int `json:"premium_subscription_count,omitempty"` PreferredLocale string `json:"preferred_locale"` PublicUpdatesChannelId objects.NullableSnowflake `json:"public_updates_channel_id"` - MaxVideoChannelUsers int `json:"max_video_channel_users"` - ApproximateMemberCount int `json:"approximate_member_count"` // Returned on GET /guild/:id - ApproximatePresenceCount int `json:"approximate_presence_count"` // Returned on GET /guild/:id - WelcomeScreen WelcomeScreen `json:"welcome_screen"` - Nsfw bool `json:"nsfw"` + MaxVideoChannelUsers *int `json:"max_video_channel_users,omitempty"` + MaxStageVideoChannelUsers *int `json:"max_stage_video_channel_users,omitempty"` + ApproximateMemberCount int `json:"approximate_member_count,omitempty"` + ApproximatePresenceCount int `json:"approximate_presence_count,omitempty"` + WelcomeScreen *WelcomeScreen `json:"welcome_screen,omitempty"` + NsfwLevel int `json:"nsfw_level"` + Stickers []sticker.Sticker `json:"stickers,omitempty"` + PremiumProgressBarEnabled bool `json:"premium_progress_bar_enabled"` + SafetyAlertsChannelId objects.NullableSnowflake `json:"safety_alerts_channel_id"` + IncidentsData *IncidentsData `json:"incidents_data,omitempty"` +} + +type IncidentsData struct { + InvitesDisabledUntil *time.Time `json:"invites_disabled_until,omitempty"` + DmsDisabledUntil *time.Time `json:"dms_disabled_until,omitempty"` + DmSpamDetectedAt *time.Time `json:"dm_spam_detected_at,omitempty"` + RaidDetectedAt *time.Time `json:"raid_detected_at,omitempty"` } func (g *Guild) IconUrl() string { - if g.Icon == "" { + if g.Icon == nil || *g.Icon == "" { return "" } extension := "png" - if strings.HasPrefix(g.Icon, "a_") { + if strings.HasPrefix(*g.Icon, "a_") { extension = "gif" } - return fmt.Sprintf("https://cdn.discordapp.com/icons/%d/%s.%s", g.Id, g.Icon, extension) + return fmt.Sprintf("https://cdn.discordapp.com/icons/%d/%s.%s", g.Id, *g.Icon, extension) } func (g *Guild) ToCachedGuild() (cached CachedGuild) { diff --git a/objects/guild/guildembed.go b/objects/guild/guildembed.go index 97ba327..2dbb69f 100644 --- a/objects/guild/guildembed.go +++ b/objects/guild/guildembed.go @@ -1,6 +1,9 @@ package guild +import "github.com/TicketsBot-cloud/gdl/objects" + +// GuildEmbed represents the settings for a guild's widget (also known as GuildWidgetSettings). type GuildEmbed struct { - Enabled bool `json:"enabled"` - ChannelId uint64 `json:"channel_id,string"` + Enabled bool `json:"enabled"` + ChannelId objects.NullableSnowflake `json:"channel_id"` } diff --git a/objects/guild/guildpreview.go b/objects/guild/guildpreview.go index 6742949..bb97191 100644 --- a/objects/guild/guildpreview.go +++ b/objects/guild/guildpreview.go @@ -1,16 +1,20 @@ package guild -import "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" +import ( + "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" + "github.com/TicketsBot-cloud/gdl/objects/guild/sticker" +) type GuildPreview struct { - Id uint64 `json:"id,string"` - Name string `json:"name"` - Icon string `json:"icon"` - Splash string `json:"splash"` - DiscoverySplash string `json:"discovery_splash"` - Emojis []emoji.Emoji `json:"emojis"` - Features []GuildFeature `json:"features"` - ApproximateMemberCount int `json:"approximate_member_count"` - ApproximatePresenceCount int `json:"approximate_presence_count"` - Description string `json:"description"` + Id uint64 `json:"id,string"` + Name string `json:"name"` + Icon *string `json:"icon"` + Splash *string `json:"splash"` + DiscoverySplash *string `json:"discovery_splash"` + Emojis []emoji.Emoji `json:"emojis"` + Features []GuildFeature `json:"features"` + ApproximateMemberCount int `json:"approximate_member_count"` + ApproximatePresenceCount int `json:"approximate_presence_count"` + Description *string `json:"description"` + Stickers []sticker.Sticker `json:"stickers"` } diff --git a/objects/guild/guildwidget.go b/objects/guild/guildwidget.go index d17aade..fae90a2 100644 --- a/objects/guild/guildwidget.go +++ b/objects/guild/guildwidget.go @@ -8,7 +8,7 @@ import ( type GuildWidget struct { Id uint64 `json:"id,string"` Name string `json:"name"` - InstantInvite string `json:"instant_invite"` + InstantInvite *string `json:"instant_invite"` Channels []channel.Channel `json:"channels"` Members []member.Member `json:"members"` PresenceCount int `json:"presence_count"` diff --git a/objects/guild/role.go b/objects/guild/role.go index c3c5704..ff4b57f 100644 --- a/objects/guild/role.go +++ b/objects/guild/role.go @@ -18,8 +18,13 @@ type Role struct { } type RoleTags struct { - BotId *uint64 `json:"bot_id,string,omitempty"` - IntegrationId *uint64 `json:"integration_id,string,omitempty"` + BotId *uint64 `json:"bot_id,string,omitempty"` + IntegrationId *uint64 `json:"integration_id,string,omitempty"` + // PremiumSubscriber, AvailableForPurchase, GuildConnections: key present (even as null) = tag applies + PremiumSubscriber *bool `json:"premium_subscriber,omitempty"` + SubscriptionListingId *uint64 `json:"subscription_listing_id,string,omitempty"` + AvailableForPurchase *bool `json:"available_for_purchase,omitempty"` + GuildConnections *bool `json:"guild_connections,omitempty"` } func (r *Role) Mention() string { diff --git a/objects/guild/welcomescreen.go b/objects/guild/welcomescreen.go index 695e260..8fb5330 100644 --- a/objects/guild/welcomescreen.go +++ b/objects/guild/welcomescreen.go @@ -3,7 +3,7 @@ package guild import "github.com/TicketsBot-cloud/gdl/objects" type WelcomeScreen struct { - Description string `json:"description"` + Description *string `json:"description"` WelcomeChannels []WelcomeScreenChannel `json:"welcome_channels"` } diff --git a/objects/integration/integrations.go b/objects/integration/integrations.go index b024813..7d9792e 100644 --- a/objects/integration/integrations.go +++ b/objects/integration/integrations.go @@ -8,16 +8,28 @@ import ( ) type Integration struct { - Id uint64 `json:"id,string"` - Name string `json:"name"` - Type string `json:"type"` // twitch, youtube, etc. - Enabled bool `json:"enabled"` - Syncing bool `json:"syncing"` - RoleId uint64 `json:"role_id,string"` - EnableEmoticons bool `json:"enable_emoticons"` - ExpireBehaviour IntegrationExpireBehaviour `json:"expire_behavior"` - ExpireGracePeriod int `json:"expire_grace_period"` - User user.User `json:"user"` - Account guild.Account `json:"account"` - SyncedAt time.Time `json:"synced_at"` + Id uint64 `json:"id,string"` + Name string `json:"name"` + Type string `json:"type"` // twitch, youtube, discord, etc. + Enabled bool `json:"enabled"` + Syncing *bool `json:"syncing,omitempty"` + RoleId *uint64 `json:"role_id,string,omitempty"` + EnableEmoticons *bool `json:"enable_emoticons,omitempty"` + ExpireBehaviour *IntegrationExpireBehaviour `json:"expire_behavior,omitempty"` + ExpireGracePeriod *int `json:"expire_grace_period,omitempty"` + User *user.User `json:"user,omitempty"` + Account guild.Account `json:"account"` + SyncedAt *time.Time `json:"synced_at,omitempty"` + SubscriberCount *int `json:"subscriber_count,omitempty"` + Revoked *bool `json:"revoked,omitempty"` + Application *IntegrationApplication `json:"application,omitempty"` + Scopes []string `json:"scopes,omitempty"` +} + +type IntegrationApplication struct { + Id uint64 `json:"id,string"` + Name string `json:"name"` + Icon *string `json:"icon"` + Description string `json:"description"` + Bot *user.User `json:"bot,omitempty"` } From e8467c14b79f52833dcccbd583ae854bee80cbe3 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 23:45:38 +0100 Subject: [PATCH 21/73] Expand GuildFeature constants Replace the previous minimal set of GuildFeature constants with an expanded list to reflect newer Discord guild feature flags. Adds many new entries (e.g., ANIMATED_BANNER, ANIMATED_ICON, APPLICATION_COMMAND_PERMISSIONS_V2, AUTO_MODERATION, COMMUNITY, ROLE_SUBSCRIPTIONS_*, TICKETED_EVENTS_ENABLED, WELCOME_SCREEN_ENABLED, and others) while preserving existing flags like INVITE_SPLASH, VIP_REGIONS, VERIFIED, PARTNERED, NEWS, BANNER, FEATURABLE, and VANITY_URL. This update brings the code in line with updated Discord API feature flags. https://docs.discord.com/developers/resources/guild#guild-object-guild-features --- objects/guild/guildfeature.go | 44 +++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/objects/guild/guildfeature.go b/objects/guild/guildfeature.go index 334ad16..13d8576 100644 --- a/objects/guild/guildfeature.go +++ b/objects/guild/guildfeature.go @@ -3,16 +3,36 @@ package guild type GuildFeature string const ( - GuildFeatureInviteSplash GuildFeature = "INVITE_SPLASH" - GuildFeatureVipRegions GuildFeature = "VIP_REGIONS" // guild has access to set 384kbps bitrate in voice (previously VIP voice servers) - GuildFeatureVanityUrl GuildFeature = "VANITY_URL" - GuildFeatureVerified GuildFeature = "VERIFIED" - GuildFeaturePartnered GuildFeature = "PARTNERED" - GuildFeaturePublic GuildFeature = "PUBLIC" - GuildFeatureCommerce GuildFeature = "COMMERCE" - GuildFeatureNews GuildFeature = "NEWS" - GuildFeatureDiscoverable GuildFeature = "DISCOVERABLE" - GuildFeatureFeaturable GuildFeature = "FEATURABLE" - GuildFeatureBanner GuildFeature = "BANNER" - GuildFeaturePublicDisabled GuildFeature = "PUBLIC_DISABLED" + GuildFeatureAnimatedBanner GuildFeature = "ANIMATED_BANNER" + GuildFeatureAnimatedIcon GuildFeature = "ANIMATED_ICON" + GuildFeatureApplicationCommandPermissionsV2 GuildFeature = "APPLICATION_COMMAND_PERMISSIONS_V2" + GuildFeatureAutoModeration GuildFeature = "AUTO_MODERATION" + GuildFeatureBanner GuildFeature = "BANNER" + GuildFeatureCommunity GuildFeature = "COMMUNITY" + GuildFeatureCreatorMonetizableProvisional GuildFeature = "CREATOR_MONETIZABLE_PROVISIONAL" + GuildFeatureCreatorStorePage GuildFeature = "CREATOR_STORE_PAGE" + GuildFeatureDeveloperSupportServer GuildFeature = "DEVELOPER_SUPPORT_SERVER" + GuildFeatureDiscoverable GuildFeature = "DISCOVERABLE" + GuildFeatureFeaturable GuildFeature = "FEATURABLE" + GuildFeatureEnhancedRoleColors GuildFeature = "ENHANCED_ROLE_COLORS" + GuildFeatureGuestsEnabled GuildFeature = "GUESTS_ENABLED" + GuildFeatureGuildTags GuildFeature = "GUILD_TAGS" + GuildFeatureInvitesDisabled GuildFeature = "INVITES_DISABLED" + GuildFeatureInviteSplash GuildFeature = "INVITE_SPLASH" + GuildFeatureMemberVerificationGateEnabled GuildFeature = "MEMBER_VERIFICATION_GATE_ENABLED" + GuildFeatureMoreSoundboard GuildFeature = "MORE_SOUNDBOARD" + GuildFeatureMoreStickers GuildFeature = "MORE_STICKERS" + GuildFeatureNews GuildFeature = "NEWS" + GuildFeaturePartnered GuildFeature = "PARTNERED" + GuildFeaturePreviewEnabled GuildFeature = "PREVIEW_ENABLED" + GuildFeatureRaidAlertsDisabled GuildFeature = "RAID_ALERTS_DISABLED" + GuildFeatureRoleIcons GuildFeature = "ROLE_ICONS" + GuildFeatureRoleSubscriptionsAvailableForPurchase GuildFeature = "ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE" + GuildFeatureRoleSubscriptionsEnabled GuildFeature = "ROLE_SUBSCRIPTIONS_ENABLED" + GuildFeatureSoundboard GuildFeature = "SOUNDBOARD" + GuildFeatureTicketedEventsEnabled GuildFeature = "TICKETED_EVENTS_ENABLED" + GuildFeatureVanityUrl GuildFeature = "VANITY_URL" + GuildFeatureVerified GuildFeature = "VERIFIED" + GuildFeatureVipRegions GuildFeature = "VIP_REGIONS" + GuildFeatureWelcomeScreenEnabled GuildFeature = "WELCOME_SCREEN_ENABLED" ) From b67623e474b5a0d71c34065da575e77c5dd66a21 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 2 Mar 2026 23:55:59 +0100 Subject: [PATCH 22/73] Update Webhook object and add webhook type Make Webhook fields nullable/optional to match API semantics: GuildId and ChannelId use pointer/NullableSnowflake types, User/Name/Avatar are now optional pointers. Add SourceGuild struct and SourceChannel/Url fields for channel follower webhooks. Also add WebhookTypeApplication constant (3) and import channel package for PartialChannel. https://docs.discord.com/developers/resources/webhook#webhook-object-webhook-types --- objects/guild/webhook.go | 21 ++++++++++++++++----- objects/guild/webhooktype.go | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/objects/guild/webhook.go b/objects/guild/webhook.go index e7d2280..5e57fe3 100644 --- a/objects/guild/webhook.go +++ b/objects/guild/webhook.go @@ -2,17 +2,28 @@ package guild import ( "github.com/TicketsBot-cloud/gdl/objects" + "github.com/TicketsBot-cloud/gdl/objects/channel" "github.com/TicketsBot-cloud/gdl/objects/user" ) type Webhook struct { Id uint64 `json:"id,string"` Type WebhookType `json:"type"` - GuildId uint64 `json:"guild_id,string,omitempty"` - ChannelId uint64 `json:"channel_id,string"` - User user.User `json:"user"` - Name string `json:"name,omitempty"` - Avatar string `json:"avatar,omitempty"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + ChannelId objects.NullableSnowflake `json:"channel_id"` + User *user.User `json:"user,omitempty"` + Name *string `json:"name"` + Avatar *string `json:"avatar"` Token string `json:"token,omitempty"` ApplicationId objects.NullableSnowflake `json:"application_id"` + SourceGuild *WebhookSourceGuild `json:"source_guild,omitempty"` + SourceChannel *channel.PartialChannel `json:"source_channel,omitempty"` + Url *string `json:"url,omitempty"` +} + +// WebhookSourceGuild is the partial guild object returned for Channel Follower webhooks. +type WebhookSourceGuild struct { + Id uint64 `json:"id,string"` + Name string `json:"name"` + Icon *string `json:"icon"` } diff --git a/objects/guild/webhooktype.go b/objects/guild/webhooktype.go index 4b24392..eed070f 100644 --- a/objects/guild/webhooktype.go +++ b/objects/guild/webhooktype.go @@ -5,4 +5,5 @@ type WebhookType int const ( WebhookTypeIncoming WebhookType = 1 WebhookTypeChannelFollower WebhookType = 2 + WebhookTypeApplication WebhookType = 3 ) From aa04dfdaa227204d851968e44849cf12ca350338 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:03:13 +0100 Subject: [PATCH 23/73] Rename enums and update Connection struct Rename Visibility -> ConnectionVisibility and update its constants; change Connection struct fields: Revoked is now *bool with omitempty, Integrations is omitempty, added TwoWayLink, adjusted Type comment, and Visibility uses the new ConnectionVisibility type. Also rename IntegrationExpireBehaviour constants to prefixed names (IntegrationExpireBehaviourRemoveRole, IntegrationExpireBehaviourKick) for clarity. https://docs.discord.com/developers/resources/guild#integration-object --- objects/integration/connection.go | 25 ++++++++++--------- .../integration/integrationexpirebehaviour.go | 4 +-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/objects/integration/connection.go b/objects/integration/connection.go index 83a46fb..1180642 100644 --- a/objects/integration/connection.go +++ b/objects/integration/connection.go @@ -1,20 +1,21 @@ package integration -type Visibility int +type ConnectionVisibility int const ( - VisibilityNone Visibility = 0 - VisibilityEveryone Visibility = 1 + ConnectionVisibilityNone ConnectionVisibility = 0 + ConnectionVisibilityEveryone ConnectionVisibility = 1 ) type Connection struct { - Id string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` // youtube, twitch, etc. - Revoked bool `json:"revoked"` - Integrations []Integration `json:"integrations"` - Verified bool `json:"verified"` - FriendSync bool `json:"friend_sync"` - ShowActivity bool `json:"show_activity"` - Visibility Visibility `json:"visibility"` + Id string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` // twitch, youtube, spotify, etc. + Revoked *bool `json:"revoked,omitempty"` + Integrations []Integration `json:"integrations,omitempty"` + Verified bool `json:"verified"` + FriendSync bool `json:"friend_sync"` + ShowActivity bool `json:"show_activity"` + TwoWayLink bool `json:"two_way_link"` + Visibility ConnectionVisibility `json:"visibility"` } diff --git a/objects/integration/integrationexpirebehaviour.go b/objects/integration/integrationexpirebehaviour.go index b1eb94e..b32bb64 100644 --- a/objects/integration/integrationexpirebehaviour.go +++ b/objects/integration/integrationexpirebehaviour.go @@ -3,6 +3,6 @@ package integration type IntegrationExpireBehaviour int const ( - RemoveRole IntegrationExpireBehaviour = 0 - Kick IntegrationExpireBehaviour = 1 + IntegrationExpireBehaviourRemoveRole IntegrationExpireBehaviour = 0 + IntegrationExpireBehaviourKick IntegrationExpireBehaviour = 1 ) From 38d0b8842a6d33923574f5dd13910474303f724b Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:06:02 +0100 Subject: [PATCH 24/73] Rename ComponentSelectMenu to ComponentStringSelect Replace occurrences of ComponentSelectMenu with ComponentStringSelect across component types and handling. Updated the Component enum, component UnmarshalJSON switch, SelectMenu Type/MarshalJSON/BuildSelectMenu implementations, and select menu interaction data/type checks so the select menu is treated as a String Select component. No functional changes beyond the identifier rename. https://docs.discord.com/developers/components/reference#component-reference --- objects/interaction/component/component.go | 4 ++-- objects/interaction/component/selectmenu.go | 6 +++--- objects/interaction/componentinteractiondata.go | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/objects/interaction/component/component.go b/objects/interaction/component/component.go index f0fe555..e57a60c 100644 --- a/objects/interaction/component/component.go +++ b/objects/interaction/component/component.go @@ -11,7 +11,7 @@ type ComponentType uint8 const ( ComponentActionRow ComponentType = iota + 1 ComponentButton - ComponentSelectMenu + ComponentStringSelect ComponentInputText ComponentUserSelect ComponentRoleSelect @@ -140,7 +140,7 @@ func (c *Component) UnmarshalJSON(data []byte) error { var parsed Button err = json.Unmarshal(data, &parsed) c.ComponentData = parsed - case ComponentSelectMenu: + case ComponentStringSelect: var parsed SelectMenu err = json.Unmarshal(data, &parsed) c.ComponentData = parsed diff --git a/objects/interaction/component/selectmenu.go b/objects/interaction/component/selectmenu.go index ee17a61..cc8366b 100644 --- a/objects/interaction/component/selectmenu.go +++ b/objects/interaction/component/selectmenu.go @@ -25,7 +25,7 @@ type SelectOption struct { } func (s SelectMenu) Type() ComponentType { - return ComponentSelectMenu + return ComponentStringSelect } func (s SelectMenu) MarshalJSON() ([]byte, error) { @@ -35,14 +35,14 @@ func (s SelectMenu) MarshalJSON() ([]byte, error) { Type ComponentType `json:"type"` WrappedSelectMenu }{ - Type: ComponentSelectMenu, + Type: ComponentStringSelect, WrappedSelectMenu: WrappedSelectMenu(s), }) } func BuildSelectMenu(data SelectMenu) Component { return Component{ - Type: ComponentSelectMenu, + Type: ComponentStringSelect, ComponentData: data, } } diff --git a/objects/interaction/componentinteractiondata.go b/objects/interaction/componentinteractiondata.go index 6ad8abd..89636df 100644 --- a/objects/interaction/componentinteractiondata.go +++ b/objects/interaction/componentinteractiondata.go @@ -58,7 +58,7 @@ type SelectMenuInteractionData struct { } func (d SelectMenuInteractionData) Type() component.ComponentType { - return component.ComponentSelectMenu + return component.ComponentStringSelect } type FileUploadInteractionData struct { @@ -118,7 +118,7 @@ func (d *MessageComponentInteractionData) UnmarshalJSON(data []byte) error { var parsed ButtonInteractionData err = json.Unmarshal(data, &parsed) d.IMessageComponentInteractionData = parsed - case component.ComponentSelectMenu: + case component.ComponentStringSelect: var parsed SelectMenuInteractionData err = json.Unmarshal(data, &parsed) d.IMessageComponentInteractionData = parsed From 09a28d37bd04844df3fd577b49cc33cb8860143a Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:16:57 +0100 Subject: [PATCH 25/73] Update application command structs and option types Extend and modernize ApplicationCommand and ApplicationCommandOption definitions: rename/standardize JSON tags, add new fields (guild_id, default_member_permissions, nsfw, version), and make several fields optional (options, focused, required, autocomplete). Add numeric/string bounds (min_value, max_value, min_length, max_length) for options and introduce a new ApplicationCommandType constant (PrimaryEntryPoint). Also rename option enum constants to more explicit ApplicationCommandOptionType* names. These changes align the types with updated API field names and optionality, and improve validation support for option values. https://docs.discord.com/developers/interactions/application-commands#application-commands --- objects/interaction/applicationcommand.go | 20 ++++++----- .../interaction/applicationcommandoption.go | 33 ++++++++++--------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/objects/interaction/applicationcommand.go b/objects/interaction/applicationcommand.go index 5d57449..07c5f05 100644 --- a/objects/interaction/applicationcommand.go +++ b/objects/interaction/applicationcommand.go @@ -1,14 +1,17 @@ package interaction type ApplicationCommand struct { - Id uint64 `json:"id,string,omitempty"` - Type ApplicationCommandType `json:"application_command_type"` - ApplicationId uint64 `json:"application_id,string,omitempty"` - Name string `json:"name"` - Description string `json:"description"` - Options []ApplicationCommandOption `json:"options"` - DefaultPermission bool `json:"default_permission,omitempty"` - Contexts []InteractionContextType `json:"contexts,omitempty"` + Id uint64 `json:"id,string,omitempty"` + Type ApplicationCommandType `json:"type"` + ApplicationId uint64 `json:"application_id,string,omitempty"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + Name string `json:"name"` + Description string `json:"description"` + Options []ApplicationCommandOption `json:"options,omitempty"` + DefaultMemberPermissions *string `json:"default_member_permissions,omitempty"` + Nsfw bool `json:"nsfw,omitempty"` + Version uint64 `json:"version,string,omitempty"` + Contexts []InteractionContextType `json:"contexts,omitempty"` } type ApplicationCommandType uint8 @@ -17,4 +20,5 @@ const ( ApplicationCommandTypeChatInput ApplicationCommandType = iota + 1 ApplicationCommandTypeUser ApplicationCommandTypeMessage + ApplicationCommandTypePrimaryEntryPoint ) diff --git a/objects/interaction/applicationcommandoption.go b/objects/interaction/applicationcommandoption.go index 4448792..e6fbfd1 100644 --- a/objects/interaction/applicationcommandoption.go +++ b/objects/interaction/applicationcommandoption.go @@ -6,35 +6,38 @@ type ApplicationCommandInteractionDataOption struct { Name string `json:"name"` Value interface{} `json:"value,omitempty"` Options []ApplicationCommandInteractionDataOption `json:"options,omitempty"` - Focused bool `json:"focused"` + Focused bool `json:"focused,omitempty"` } type ApplicationCommandOption struct { Type ApplicationCommandOptionType `json:"type"` Name string `json:"name"` Description string `json:"description"` - Default bool `json:"default"` - Required bool `json:"required"` + Required bool `json:"required,omitempty"` Choices []ApplicationCommandOptionChoice `json:"choices,omitempty"` - Autocomplete bool `json:"autocomplete"` + Autocomplete bool `json:"autocomplete,omitempty"` Options []ApplicationCommandOption `json:"options,omitempty"` ChannelTypes []channel.ChannelType `json:"channel_types,omitempty"` + MinValue *float64 `json:"min_value,omitempty"` + MaxValue *float64 `json:"max_value,omitempty"` + MinLength *int `json:"min_length,omitempty"` + MaxLength *int `json:"max_length,omitempty"` } type ApplicationCommandOptionType uint8 const ( - OptionTypeSubCommand ApplicationCommandOptionType = iota + 1 - OptionTypeSubCommandGroup - OptionTypeString - OptionTypeInteger - OptionTypeBoolean - OptionTypeUser - OptionTypeChannel - OptionTypeRole - OptionTypeMentionable - OptionTypeNumber - OptionTypeAttachment + ApplicationCommandOptionTypeSubCommand ApplicationCommandOptionType = iota + 1 + ApplicationCommandOptionTypeSubCommandGroup + ApplicationCommandOptionTypeString + ApplicationCommandOptionTypeInteger + ApplicationCommandOptionTypeBoolean + ApplicationCommandOptionTypeUser + ApplicationCommandOptionTypeChannel + ApplicationCommandOptionTypeRole + ApplicationCommandOptionTypeMentionable + ApplicationCommandOptionTypeNumber + ApplicationCommandOptionTypeAttachment ) type ApplicationCommandOptionChoice struct { From 190b2e443f3a927aaff089379b916387b9e1a351 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:30:57 +0100 Subject: [PATCH 26/73] Rename and realign interaction response types Rename several ResponseType constants and realign their numeric values. ACKWithSource was renamed to DeferredChannelMessageWithSource and DeferredMessageUpdate to DeferredUpdateMessage; response constructors were updated accordingly. Const blocks were restructured to adjust iota offsets (e.g. Pong is now 0), PremiumRequired marked deprecated, and a new LaunchActivity constant was added. Note: this changes constant names and their numeric assignments, which may be a breaking change for code relying on the previous values. https://docs.discord.com/developers/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type --- objects/interaction/response.go | 4 ++-- objects/interaction/responsetype.go | 19 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/objects/interaction/response.go b/objects/interaction/response.go index ef09337..ac1e4ca 100644 --- a/objects/interaction/response.go +++ b/objects/interaction/response.go @@ -54,7 +54,7 @@ type ResponseAckWithSource struct { func NewResponseAckWithSource(flags uint) ResponseAckWithSource { return ResponseAckWithSource{ Response: Response{ - Type: ResponseTypeACKWithSource, + Type: ResponseTypeDeferredChannelMessageWithSource, }, Data: struct { Flags uint `json:"flags"` @@ -74,7 +74,7 @@ type ResponseDeferredMessageUpdate struct { func NewResponseDeferredMessageUpdate() ResponseDeferredMessageUpdate { return ResponseDeferredMessageUpdate{ Response: Response{ - Type: ResponseTypeDeferredMessageUpdate, + Type: ResponseTypeDeferredUpdateMessage, }, } } diff --git a/objects/interaction/responsetype.go b/objects/interaction/responsetype.go index 319bc6e..3400953 100644 --- a/objects/interaction/responsetype.go +++ b/objects/interaction/responsetype.go @@ -3,14 +3,13 @@ package interaction type ResponseType uint8 const ( - ResponseTypePong ResponseType = iota + 1 - _ - _ - ResponseTypeChannelMessageWithSource - ResponseTypeACKWithSource - ResponseTypeDeferredMessageUpdate - ResponseTypeUpdateMessage - ResponseTypeApplicationCommandAutoCompleteResult - ResponseTypeModal - ResponseTypePremiumRequired + ResponseTypePong ResponseType = 1 + ResponseTypeChannelMessageWithSource ResponseType = 4 + ResponseTypeDeferredChannelMessageWithSource ResponseType = 5 + ResponseTypeDeferredUpdateMessage ResponseType = 6 + ResponseTypeUpdateMessage ResponseType = 7 + ResponseTypeApplicationCommandAutoCompleteResult ResponseType = 8 + ResponseTypeModal ResponseType = 9 + ResponseTypePremiumRequired ResponseType = 10 // Deprecated + ResponseTypeLaunchActivity ResponseType = 12 ) From 11b09784a5f9f83d66a9067f4c6be8107bd348c6 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:32:46 +0100 Subject: [PATCH 27/73] Refactor Invite model and REST payload Revamp Invite types and fields to match updated Discord API payloads. Introduces InviteType and InviteTargetType enums, adds/renames fields on Invite (Type, TargetType, TargetApplication, ExpiresAt, GuildScheduledEvent, Flags, Roles), and converts several fields to pointers with omitempty (Guild, Channel -> PartialChannel, Inviter, TargetUser). Also updates CreateInviteData to use TargetType JSON field name and imports application and scheduledevent packages. These changes allow support for embedded applications, scheduled events and optional invite properties; note this is a breaking change to the Invite structure and JSON tags. https://docs.discord.com/developers/resources/invite#invite-resource --- objects/invite/invite.go | 37 +++++++++++++++++++++++++++---------- rest/channel.go | 2 +- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/objects/invite/invite.go b/objects/invite/invite.go index 9a78217..7716639 100644 --- a/objects/invite/invite.go +++ b/objects/invite/invite.go @@ -3,26 +3,43 @@ package invite import ( "time" + "github.com/TicketsBot-cloud/gdl/objects/application" "github.com/TicketsBot-cloud/gdl/objects/channel" "github.com/TicketsBot-cloud/gdl/objects/guild" + "github.com/TicketsBot-cloud/gdl/objects/guild/scheduledevent" "github.com/TicketsBot-cloud/gdl/objects/user" ) -type TargetUserType int +type InviteType int const ( - STREAM TargetUserType = 1 + InviteTypeGuild InviteType = 0 + InviteTypeGroupDm InviteType = 1 + InviteTypeFriend InviteType = 2 +) + +type InviteTargetType int + +const ( + InviteTargetTypeStream InviteTargetType = 1 + InviteTargetTypeEmbeddedApplication InviteTargetType = 2 ) type Invite struct { - Code string `json:"code"` - Guild guild.Guild `json:"guild"` - Channel channel.Channel `json:"channel"` - Inviter user.User `json:"inviter"` - TargetUser user.User `json:"target_user"` - TargetUserType TargetUserType `json:"target_user_type"` - ApproximatePresenceCount int `json:"approximate_presence_count"` - ApproximateMemberCount int `json:"approximate_member_count"` + Type InviteType `json:"type"` + Code string `json:"code"` + Guild *guild.Guild `json:"guild,omitempty"` + Channel *channel.PartialChannel `json:"channel,omitempty"` + Inviter *user.User `json:"inviter,omitempty"` + TargetType InviteTargetType `json:"target_type,omitempty"` + TargetUser *user.User `json:"target_user,omitempty"` + TargetApplication *application.Application `json:"target_application,omitempty"` + ApproximatePresenceCount int `json:"approximate_presence_count,omitempty"` + ApproximateMemberCount int `json:"approximate_member_count,omitempty"` + ExpiresAt *time.Time `json:"expires_at,omitempty"` + GuildScheduledEvent *scheduledevent.GuildScheduledEvent `json:"guild_scheduled_event,omitempty"` + Flags *int `json:"flags,omitempty"` + Roles []guild.Role `json:"roles,omitempty"` } type InviteMetadata struct { diff --git a/rest/channel.go b/rest/channel.go index b0eb44f..ee8a177 100644 --- a/rest/channel.go +++ b/rest/channel.go @@ -414,7 +414,7 @@ type CreateInviteData struct { Temporary bool `json:"temporary"` Unique bool `json:"unique"` TargetUser uint64 `json:"target_user,string,omitempty"` - TargetUserType int `json:"target_user_type,omitempty"` + TargetType int `json:"target_type,omitempty"` } func CreateChannelInvite(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64, data CreateInviteData) (invite.Invite, error) { From f79a4cb794ab9a6ef0e5fe300dec2e6b04449179 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:36:16 +0100 Subject: [PATCH 28/73] Add AvatarDecorationData; mark fields omitempty Add AvatarDecorationData struct and include it on Member to support avatar decoration metadata. Also add `omitempty` to Pending, Permissions and CommunicationDisabledUntil JSON tags to avoid emitting null/empty values during serialization and tidy up struct field formatting. https://docs.discord.com/developers/resources/guild#guild-member-object --- objects/member/member.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/objects/member/member.go b/objects/member/member.go index 6b7f0af..532abe0 100644 --- a/objects/member/member.go +++ b/objects/member/member.go @@ -17,10 +17,16 @@ type Member struct { PremiumSince *time.Time `json:"premium_since"` Deaf bool `json:"deaf"` Mute bool `json:"mute"` - Flags int `json:"flags"` - Pending *bool `json:"pending"` - Permissions uint64 `json:"permissions,string"` - CommunicationDisabledUntil *time.Time `json:"communication_disabled_until"` + Flags int `json:"flags"` + Pending *bool `json:"pending,omitempty"` + Permissions uint64 `json:"permissions,string,omitempty"` + CommunicationDisabledUntil *time.Time `json:"communication_disabled_until,omitempty"` + AvatarDecorationData *AvatarDecorationData `json:"avatar_decoration_data,omitempty"` +} + +type AvatarDecorationData struct { + Asset string `json:"asset"` + SkuId uint64 `json:"sku_id,string"` } func (m *Member) HasRole(roleId uint64) bool { From 09c486f286f3aaa450c1f0e3032815bebb43e99a Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:37:58 +0100 Subject: [PATCH 29/73] Add omitempty to SoundboardSound GuildId Update the SoundboardSound struct's GuildId field tag to include `omitempty` (`guild_id,string,omitempty`). This ensures a nil GuildId pointer is omitted from JSON output instead of being emitted, improving marshaling behavior when the guild ID is absent. No functional logic changes. https://docs.discord.com/developers/resources/soundboard#soundboard-resource --- objects/soundboard/soundboard.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objects/soundboard/soundboard.go b/objects/soundboard/soundboard.go index e9d4c6a..17275c4 100644 --- a/objects/soundboard/soundboard.go +++ b/objects/soundboard/soundboard.go @@ -8,7 +8,7 @@ type SoundboardSound struct { Volume float64 `json:"volume"` EmojiId *uint64 `json:"emoji_id,string"` EmojiName *string `json:"emoji_name,omitempty"` - GuildId *uint64 `json:"guild_id,string"` + GuildId *uint64 `json:"guild_id,string,omitempty"` Available bool `json:"available"` User *user.User `json:"user,omitempty"` } From 70d7f0af7b1dcf6181c9d0bb55112a4d09ccaf3e Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:42:24 +0100 Subject: [PATCH 30/73] Use StagePrivacyLevel and nullable event ID Introduce StagePrivacyLevel enum and switch StageInstance.PrivacyLevel from int to this new type for stronger typing. Change GuildScheduledEventId from *uint64 to objects.NullableSnowflake to handle JSON nulls more explicitly and remove the `,string` tag. Make DiscoverableDisabled omit empty values in JSON and add the required import for objects. https://docs.discord.com/developers/resources/stage-instance#stage-instance-resource --- objects/stage/stage.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/objects/stage/stage.go b/objects/stage/stage.go index 9f09d0c..1406b6f 100644 --- a/objects/stage/stage.go +++ b/objects/stage/stage.go @@ -1,11 +1,20 @@ package stage +import "github.com/TicketsBot-cloud/gdl/objects" + +type StagePrivacyLevel int + +const ( + StagePrivacyLevelPublic StagePrivacyLevel = 1 // Deprecated + StagePrivacyLevelGuildOnly StagePrivacyLevel = 2 +) + type StageInstance struct { - Id uint64 `json:"id,string"` - GuildId uint64 `json:"guild_id,string"` - ChannelId uint64 `json:"channel_id,string"` - Topic string `json:"topic"` - PrivacyLevel int `json:"privacy_level"` - DiscoverableDisabled bool `json:"discoverable_disabled"` - GuildScheduledEventId *uint64 `json:"guild_scheduled_event_id,string"` + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + ChannelId uint64 `json:"channel_id,string"` + Topic string `json:"topic"` + PrivacyLevel StagePrivacyLevel `json:"privacy_level"` + DiscoverableDisabled bool `json:"discoverable_disabled,omitempty"` + GuildScheduledEventId objects.NullableSnowflake `json:"guild_scheduled_event_id"` } From 51d8361622f5a8ad27b641c75ecd7fdace4604f7 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:45:35 +0100 Subject: [PATCH 31/73] Rename Status to SubscriptionStatus; add omitempty Rename the Status type to SubscriptionStatus and update related constants and the Subscription.Status field to use the new type. Also add `omitempty` to the RenewalSkuIds JSON tag so empty renewal SKU slices are omitted during marshaling. https://docs.discord.com/developers/resources/subscription#subscription-resource --- objects/subscription/subscription.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/objects/subscription/subscription.go b/objects/subscription/subscription.go index 1a27d7f..a7923d0 100644 --- a/objects/subscription/subscription.go +++ b/objects/subscription/subscription.go @@ -6,12 +6,12 @@ import ( "github.com/TicketsBot-cloud/gdl/utils" ) -type Status int +type SubscriptionStatus int const ( - StatusActive Status = iota - StatusEnding - StatusInactive + SubscriptionStatusActive SubscriptionStatus = iota + SubscriptionStatusEnding + SubscriptionStatusInactive ) type Subscription struct { @@ -19,10 +19,10 @@ type Subscription struct { UserId uint64 `json:"user_id,string"` SkuIds utils.Uint64StringSlice `json:"sku_ids"` EntitlementIds utils.Uint64StringSlice `json:"entitlement_ids"` - RenewalSkuIds utils.Uint64StringSlice `json:"renewal_sku_ids"` + RenewalSkuIds utils.Uint64StringSlice `json:"renewal_sku_ids,omitempty"` CurrentPeriodStart time.Time `json:"current_period_start"` CurrentPeriodEnd time.Time `json:"current_period_end"` - Status Status `json:"status"` + Status SubscriptionStatus `json:"status"` CanceledAt *time.Time `json:"canceled_at,omitempty"` Country *string `json:"country,omitempty"` } From 6bea2e3e7d1716aaf62dd2a7a05213f64f489192 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 00:55:07 +0100 Subject: [PATCH 32/73] Refactor user/activity structs; add fields Make numerous user, activity and presence fields optional and align structs with updated API shapes. Key changes: - Member.AvatarDecorationData now references user.AvatarDecorationData (moved into user package). - Activity: Url, Details and State are now pointers; added CreatedAt, Instance as pointer, Buttons and ActivityButton type, and renamed/adjusted secrets field. - ClientStatus fields made optional (omitempty). - Presence: GuildId, Nick and PremiumSince made optional; Roles, PremiumSince marked omitempty and activities/client_status kept. - UpdateStatus: Since is now a pointer; Game replaced by Activities []Activity and BuildStatus updated accordingly. - User: added many new types and fields (UserFlag, PremiumType, AvatarDecorationData, Collectibles, PrimaryGuild, and additional metadata like banner, locale, flags, etc.) and adjusted existing fields for optionality. Overall these changes improve nullability handling and add support for new/expanded API fields. https://docs.discord.com/developers/resources/user#user-resource --- objects/member/member.go | 7 +-- objects/user/activity.go | 23 ++++++---- objects/user/clientstatus.go | 6 +-- objects/user/presence.go | 9 ++-- objects/user/updatestatus.go | 16 ++++--- objects/user/user.go | 82 +++++++++++++++++++++++++++++++++--- 6 files changed, 108 insertions(+), 35 deletions(-) diff --git a/objects/member/member.go b/objects/member/member.go index 532abe0..a9a363d 100644 --- a/objects/member/member.go +++ b/objects/member/member.go @@ -21,12 +21,7 @@ type Member struct { Pending *bool `json:"pending,omitempty"` Permissions uint64 `json:"permissions,string,omitempty"` CommunicationDisabledUntil *time.Time `json:"communication_disabled_until,omitempty"` - AvatarDecorationData *AvatarDecorationData `json:"avatar_decoration_data,omitempty"` -} - -type AvatarDecorationData struct { - Asset string `json:"asset"` - SkuId uint64 `json:"sku_id,string"` + AvatarDecorationData *user.AvatarDecorationData `json:"avatar_decoration_data,omitempty"` } func (m *Member) HasRole(roleId uint64) bool { diff --git a/objects/user/activity.go b/objects/user/activity.go index 9e096c0..4f29806 100644 --- a/objects/user/activity.go +++ b/objects/user/activity.go @@ -3,15 +3,22 @@ package user type Activity struct { Name string `json:"name"` Type ActivityType `json:"type"` - Url string `json:"url,omitempty"` + Url *string `json:"url,omitempty"` + CreatedAt int `json:"created_at,omitempty"` Timestamps *Timestamps `json:"timestamps,omitempty"` ApplicationId uint64 `json:"application_id,string,omitempty"` - Details string `json:"details,omitempty"` - State string `json:"state,omitempty"` + Details *string `json:"details,omitempty"` + State *string `json:"state,omitempty"` // TODO: Figure out how to handle emoji w/o import cycle - Party *Party `json:"party,omitempty"` - Assets *Asset `json:"assets,omitempty"` - Secret *Secret `json:"secret,omitempty"` - Instance bool `json:"instance,omitempty"` - Flags int `json:"flags,omitempty"` // TODO: Wrap this + Party *Party `json:"party,omitempty"` + Assets *Asset `json:"assets,omitempty"` + Secrets *Secret `json:"secrets,omitempty"` + Instance *bool `json:"instance,omitempty"` + Flags int `json:"flags,omitempty"` + Buttons []ActivityButton `json:"buttons,omitempty"` +} + +type ActivityButton struct { + Label string `json:"label"` + Url string `json:"url"` } diff --git a/objects/user/clientstatus.go b/objects/user/clientstatus.go index 1340ab9..1c2cbcf 100644 --- a/objects/user/clientstatus.go +++ b/objects/user/clientstatus.go @@ -1,7 +1,7 @@ package user type ClientStatus struct { - Desktop ClientStatusType `json:"desktop"` - Mobile ClientStatusType `json:"mobile"` - Web ClientStatusType `json:"web"` + Desktop ClientStatusType `json:"desktop,omitempty"` + Mobile ClientStatusType `json:"mobile,omitempty"` + Web ClientStatusType `json:"web,omitempty"` } diff --git a/objects/user/presence.go b/objects/user/presence.go index 939f1d0..5c26991 100644 --- a/objects/user/presence.go +++ b/objects/user/presence.go @@ -8,12 +8,11 @@ import ( type Presence struct { User User `json:"user"` - Roles utils.Uint64StringSlice `json:"roles"` - Game Activity `json:"name"` - GuildId uint64 `json:"guild_id,string"` + GuildId *uint64 `json:"guild_id,string,omitempty"` Status string `json:"status"` Activities []Activity `json:"activities"` ClientStatus ClientStatus `json:"client_status"` - PremiumSince *time.Time `json:"premium_since"` - Nick string `json:"nick"` + Roles utils.Uint64StringSlice `json:"roles,omitempty"` + PremiumSince *time.Time `json:"premium_since,omitempty"` + Nick *string `json:"nick,omitempty"` } diff --git a/objects/user/updatestatus.go b/objects/user/updatestatus.go index 8f34f7e..179c71b 100644 --- a/objects/user/updatestatus.go +++ b/objects/user/updatestatus.go @@ -1,17 +1,19 @@ package user type UpdateStatus struct { - Since int `json:"since"` // time since client went idle (unix epoch millis) - Game Activity `json:"game,omitempty"` - Status ClientStatusType `json:"status"` - Afk bool `json:"afk"` + Since *int `json:"since"` // unix time in ms when client went idle, null if not idle + Activities []Activity `json:"activities"` + Status ClientStatusType `json:"status"` + Afk bool `json:"afk"` } func BuildStatus(activityType ActivityType, status string) UpdateStatus { return UpdateStatus{ - Game: Activity{ - Name: status, - Type: activityType, + Activities: []Activity{ + { + Name: status, + Type: activityType, + }, }, Status: ClientStatusTypeOnline, } diff --git a/objects/user/user.go b/objects/user/user.go index 0c8d3ed..eb759de 100644 --- a/objects/user/user.go +++ b/objects/user/user.go @@ -1,13 +1,83 @@ package user -import "fmt" +import ( + "fmt" + + "github.com/TicketsBot-cloud/gdl/objects" +) + +type UserFlag int + +const ( + UserFlagStaff UserFlag = 1 << 0 + UserFlagPartner UserFlag = 1 << 1 + UserFlagHypesquad UserFlag = 1 << 2 + UserFlagBugHunterLevel1 UserFlag = 1 << 3 + UserFlagHypesquadOnlineHouse1 UserFlag = 1 << 6 + UserFlagHypesquadOnlineHouse2 UserFlag = 1 << 7 + UserFlagHypesquadOnlineHouse3 UserFlag = 1 << 8 + UserFlagPremiumEarlySupporter UserFlag = 1 << 9 + UserFlagTeamPseudoUser UserFlag = 1 << 10 + UserFlagBugHunterLevel2 UserFlag = 1 << 14 + UserFlagVerifiedBot UserFlag = 1 << 16 + UserFlagVerifiedDeveloper UserFlag = 1 << 17 + UserFlagCertifiedModerator UserFlag = 1 << 18 + UserFlagBotHttpInteractions UserFlag = 1 << 19 + UserFlagActiveDeveloper UserFlag = 1 << 22 +) + +type PremiumType int + +const ( + PremiumTypeNone PremiumType = 0 + PremiumTypeNitroClassic PremiumType = 1 + PremiumTypeNitro PremiumType = 2 + PremiumTypeNitroBasic PremiumType = 3 +) + +type AvatarDecorationData struct { + Asset string `json:"asset"` + SkuId uint64 `json:"sku_id,string"` +} + +type UserNameplate struct { + SkuId uint64 `json:"sku_id,string"` + Asset string `json:"asset"` + Label string `json:"label"` + Palette string `json:"palette"` +} + +type UserCollectibles struct { + Nameplate *UserNameplate `json:"nameplate,omitempty"` +} + +type UserPrimaryGuild struct { + IdentityGuildId objects.NullableSnowflake `json:"identity_guild_id"` + IdentityEnabled *bool `json:"identity_enabled,omitempty"` + Tag *string `json:"tag,omitempty"` + Badge *string `json:"badge,omitempty"` +} type User struct { - Id uint64 `json:"id,string"` - Username string `json:"username"` - GlobalName *string `json:"global_name"` - Avatar Avatar `json:"avatar"` - Bot bool `json:"bot"` + Id uint64 `json:"id,string"` + Username string `json:"username"` + Discriminator Discriminator `json:"discriminator"` + GlobalName *string `json:"global_name"` + Avatar Avatar `json:"avatar"` + Bot bool `json:"bot,omitempty"` + System *bool `json:"system,omitempty"` + MfaEnabled *bool `json:"mfa_enabled,omitempty"` + Banner *string `json:"banner,omitempty"` + AccentColor *int `json:"accent_color,omitempty"` + Locale *string `json:"locale,omitempty"` + Verified *bool `json:"verified,omitempty"` + Email *string `json:"email,omitempty"` + Flags *UserFlag `json:"flags,omitempty"` + PremiumType *PremiumType `json:"premium_type,omitempty"` + PublicFlags *UserFlag `json:"public_flags,omitempty"` + AvatarDecorationData *AvatarDecorationData `json:"avatar_decoration_data,omitempty"` + Collectibles *UserCollectibles `json:"collectibles,omitempty"` + PrimaryGuild *UserPrimaryGuild `json:"primary_guild,omitempty"` } // shortcut, ignores errors From 5075d9de13b883ae3a8f69de67e22046c7f49302 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 01:14:41 +0100 Subject: [PATCH 33/73] Update auditlog structs & enums for new fields Align audit log types with Discord API updates: add new fields (application commands, automoderation rules, threads, guild scheduled events, etc.) and imports in AuditLog; extend AuditEntryInfo with many optional fields and use pointer/string types for optional IDs/counts; make AuditLogChange values optional with omitempty; make AuditLogEntry use pointers and omitempty for optional fields; add numerous new AuditLogEvent constants and rename to AuditLogEvent* style; expand ChangeKey constants for new guild/channel/role/thread/soundboard/command permission keys. These changes improve compatibility with the latest audit log payloads and handle previously-optional/missing values safely. https://docs.discord.com/developers/resources/audit-log#audit-logs-resource --- objects/auditlog/auditentryinfo.go | 20 +++--- objects/auditlog/auditlog.go | 15 ++-- objects/auditlog/auditlogchange.go | 4 +- objects/auditlog/auditlogentry.go | 10 +-- objects/auditlog/auditlogevent.go | 109 ++++++++++++++++++++--------- objects/auditlog/changekey.go | 33 +++++++++ objects/auditlog/entitytype.go | 4 +- 7 files changed, 139 insertions(+), 56 deletions(-) diff --git a/objects/auditlog/auditentryinfo.go b/objects/auditlog/auditentryinfo.go index 0397da6..a8ab7e8 100644 --- a/objects/auditlog/auditentryinfo.go +++ b/objects/auditlog/auditentryinfo.go @@ -2,12 +2,16 @@ package auditlog // https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-optional-audit-entry-info type AuditEntryInfo struct { - DeleteMemberDays int `json:"delete_member_days,string"` // MEMBER_PRUNE - MembersRemoved int `json:"members_removed,string"` // MEMBER_PRUNE - ChannelId uint64 `json:"channel_id,string"` // MEMBER_MOVE & MESSAGE_PIN & MESSAGE_UNPIN & MESSAGE_DELETE - MessageId uint64 `json:"message_id,string"` // MESSAGE_PIN & MESSAGE_UNPIN - Id uint64 `json:"id,string"` // MESSAGE_DELETE & MESSAGE_BULK_DELETE & MEMBER_DISCONNECT & MEMBER_MOVE - Count int `json:"count,string"` // CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE - Type EntityType `json:"type"` // CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE - RoleName string `json:"role_name"` //CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE + ApplicationId *uint64 `json:"application_id,string,omitempty"` // APPLICATION_COMMAND_PERMISSION_UPDATE + AutoModerationRuleName string `json:"auto_moderation_rule_name,omitempty"` // AUTO_MODERATION_* + AutoModerationRuleTriggerType string `json:"auto_moderation_rule_trigger_type,omitempty"` // AUTO_MODERATION_* + ChannelId *uint64 `json:"channel_id,string,omitempty"` // MEMBER_MOVE & MESSAGE_PIN & MESSAGE_UNPIN & MESSAGE_DELETE & STAGE_INSTANCE_* + Count string `json:"count,omitempty"` // MESSAGE_DELETE & MESSAGE_BULK_DELETE & MEMBER_DISCONNECT & MEMBER_MOVE + DeleteMemberDays string `json:"delete_member_days,omitempty"` // MEMBER_PRUNE + Id *uint64 `json:"id,string,omitempty"` // MESSAGE_DELETE & MESSAGE_BULK_DELETE & MEMBER_DISCONNECT & MEMBER_MOVE + IntegrationType string `json:"integration_type,omitempty"` // MEMBER_KICK & MEMBER_ROLE_UPDATE + MembersRemoved string `json:"members_removed,omitempty"` // MEMBER_PRUNE + MessageId *uint64 `json:"message_id,string,omitempty"` // MESSAGE_PIN & MESSAGE_UNPIN + RoleName string `json:"role_name,omitempty"` // CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE + Type EntityType `json:"type,omitempty"` // CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE } diff --git a/objects/auditlog/auditlog.go b/objects/auditlog/auditlog.go index d0f2a11..337b9a2 100644 --- a/objects/auditlog/auditlog.go +++ b/objects/auditlog/auditlog.go @@ -1,14 +1,21 @@ package auditlog import ( + "github.com/TicketsBot-cloud/gdl/objects/automoderation" + "github.com/TicketsBot-cloud/gdl/objects/channel" "github.com/TicketsBot-cloud/gdl/objects/guild" "github.com/TicketsBot-cloud/gdl/objects/integration" + "github.com/TicketsBot-cloud/gdl/objects/interaction" "github.com/TicketsBot-cloud/gdl/objects/user" ) type AuditLog struct { - Webhooks []guild.Webhook `json:"webhooks"` - Users []user.User `json:"users"` - Entries []AuditLogEntry `json:"audit_log_entries"` - Integrations []integration.Integration `json:"integrations"` + ApplicationCommands []interaction.ApplicationCommand `json:"application_commands"` + AutoModerationRules []automoderation.Rule `json:"auto_moderation_rules"` + Entries []AuditLogEntry `json:"audit_log_entries"` + GuildScheduledEvents []interface{} `json:"guild_scheduled_events"` + Integrations []integration.Integration `json:"integrations"` + Threads []channel.Channel `json:"threads"` + Users []user.User `json:"users"` + Webhooks []guild.Webhook `json:"webhooks"` } diff --git a/objects/auditlog/auditlogchange.go b/objects/auditlog/auditlogchange.go index fa3edb5..0dffe82 100644 --- a/objects/auditlog/auditlogchange.go +++ b/objects/auditlog/auditlogchange.go @@ -2,7 +2,7 @@ package auditlog // https://discord.com/developers/docs/resources/audit-log#audit-log-change-object-audit-log-change-key type AuditLogChange struct { - NewValue interface{} `json:"new_value"` - OldValue interface{} `json:"old_value"` + NewValue interface{} `json:"new_value,omitempty"` + OldValue interface{} `json:"old_value,omitempty"` Key ChangeKey `json:"key"` } diff --git a/objects/auditlog/auditlogentry.go b/objects/auditlog/auditlogentry.go index f70e15f..0295741 100644 --- a/objects/auditlog/auditlogentry.go +++ b/objects/auditlog/auditlogentry.go @@ -1,11 +1,11 @@ package auditlog type AuditLogEntry struct { - TargetId uint64 `json:"target_id,string"` - Changes []AuditLogChange `json:"changes"` - UserId uint64 `json:"user_id,string"` + TargetId *string `json:"target_id"` + Changes []AuditLogChange `json:"changes,omitempty"` + UserId *uint64 `json:"user_id,string,omitempty"` Id uint64 `json:"id,string"` ActionType AuditLogEvent `json:"action_type"` - Options AuditEntryInfo `json:"options"` - Reason *string `json:"reason"` + Options *AuditEntryInfo `json:"options,omitempty"` + Reason *string `json:"reason,omitempty"` } diff --git a/objects/auditlog/auditlogevent.go b/objects/auditlog/auditlogevent.go index 546c857..3fa234f 100644 --- a/objects/auditlog/auditlogevent.go +++ b/objects/auditlog/auditlogevent.go @@ -3,39 +3,78 @@ package auditlog type AuditLogEvent int const ( - EventGuildUpdate AuditLogEvent = 1 - EventChannelCreate AuditLogEvent = 10 - EventChannelUpdate AuditLogEvent = 11 - EventChannelDelete AuditLogEvent = 12 - EventChannelOverwriteCreate AuditLogEvent = 13 - EventChannelOverwriteUpdate AuditLogEvent = 14 - EventChannelOverwriteDelete AuditLogEvent = 15 - EventMemberKick AuditLogEvent = 20 - EventMemberPrune AuditLogEvent = 21 - EventMemberBanAdd AuditLogEvent = 22 - EventMemberBanRemove AuditLogEvent = 23 - EventMemberUpdate AuditLogEvent = 24 - EventMemberRoleUpdate AuditLogEvent = 25 - EventMemberMove AuditLogEvent = 26 - EventMemberDisconnect AuditLogEvent = 27 - EventBotAdd AuditLogEvent = 28 - EventRoleCreate AuditLogEvent = 30 - EventRoleUpdate AuditLogEvent = 31 - EventRoleDelete AuditLogEvent = 32 - EventInviteCreate AuditLogEvent = 40 - EventInviteUpdate AuditLogEvent = 41 - EventInviteDelete AuditLogEvent = 42 - EventWebhookCreate AuditLogEvent = 50 - EventWebhookUpdate AuditLogEvent = 51 - EventWebhookDelete AuditLogEvent = 52 - EventEmojiCreate AuditLogEvent = 60 - EventEmojiUpdate AuditLogEvent = 61 - EventEmojiDelete AuditLogEvent = 62 - EventMessageDelete AuditLogEvent = 72 - EventMessageBulkDelete AuditLogEvent = 73 - EventMessagePin AuditLogEvent = 74 - EventMessageUnpin AuditLogEvent = 75 - EventMessageIntegrationCreate AuditLogEvent = 80 - EventMessageIntegrationUpdate AuditLogEvent = 81 - EventMessageIntegrationDelete AuditLogEvent = 82 + AuditLogEventGuildUpdate AuditLogEvent = 1 + AuditLogEventChannelCreate AuditLogEvent = 10 + AuditLogEventChannelUpdate AuditLogEvent = 11 + AuditLogEventChannelDelete AuditLogEvent = 12 + AuditLogEventChannelOverwriteCreate AuditLogEvent = 13 + AuditLogEventChannelOverwriteUpdate AuditLogEvent = 14 + AuditLogEventChannelOverwriteDelete AuditLogEvent = 15 + AuditLogEventMemberKick AuditLogEvent = 20 + AuditLogEventMemberPrune AuditLogEvent = 21 + AuditLogEventMemberBanAdd AuditLogEvent = 22 + AuditLogEventMemberBanRemove AuditLogEvent = 23 + AuditLogEventMemberUpdate AuditLogEvent = 24 + AuditLogEventMemberRoleUpdate AuditLogEvent = 25 + AuditLogEventMemberMove AuditLogEvent = 26 + AuditLogEventMemberDisconnect AuditLogEvent = 27 + AuditLogEventBotAdd AuditLogEvent = 28 + AuditLogEventRoleCreate AuditLogEvent = 30 + AuditLogEventRoleUpdate AuditLogEvent = 31 + AuditLogEventRoleDelete AuditLogEvent = 32 + AuditLogEventInviteCreate AuditLogEvent = 40 + AuditLogEventInviteUpdate AuditLogEvent = 41 + AuditLogEventInviteDelete AuditLogEvent = 42 + AuditLogEventWebhookCreate AuditLogEvent = 50 + AuditLogEventWebhookUpdate AuditLogEvent = 51 + AuditLogEventWebhookDelete AuditLogEvent = 52 + AuditLogEventEmojiCreate AuditLogEvent = 60 + AuditLogEventEmojiUpdate AuditLogEvent = 61 + AuditLogEventEmojiDelete AuditLogEvent = 62 + AuditLogEventMessageDelete AuditLogEvent = 72 + AuditLogEventMessageBulkDelete AuditLogEvent = 73 + AuditLogEventMessagePin AuditLogEvent = 74 + AuditLogEventMessageUnpin AuditLogEvent = 75 + AuditLogEventIntegrationCreate AuditLogEvent = 80 + AuditLogEventIntegrationUpdate AuditLogEvent = 81 + AuditLogEventIntegrationDelete AuditLogEvent = 82 + AuditLogEventStageInstanceCreate AuditLogEvent = 83 + AuditLogEventStageInstanceUpdate AuditLogEvent = 84 + AuditLogEventStageInstanceDelete AuditLogEvent = 85 + AuditLogEventStickerCreate AuditLogEvent = 90 + AuditLogEventStickerUpdate AuditLogEvent = 91 + AuditLogEventStickerDelete AuditLogEvent = 92 + + AuditLogEventGuildScheduledEventCreate AuditLogEvent = 100 + AuditLogEventGuildScheduledEventUpdate AuditLogEvent = 101 + AuditLogEventGuildScheduledEventDelete AuditLogEvent = 102 + + AuditLogEventThreadCreate AuditLogEvent = 110 + AuditLogEventThreadUpdate AuditLogEvent = 111 + AuditLogEventThreadDelete AuditLogEvent = 112 + + AuditLogEventApplicationCommandPermissionUpdate AuditLogEvent = 121 + + AuditLogEventSoundboardSoundCreate AuditLogEvent = 130 + AuditLogEventSoundboardSoundUpdate AuditLogEvent = 131 + AuditLogEventSoundboardSoundDelete AuditLogEvent = 132 + + AuditLogEventAutoModerationRuleCreate AuditLogEvent = 140 + AuditLogEventAutoModerationRuleUpdate AuditLogEvent = 141 + AuditLogEventAutoModerationRuleDelete AuditLogEvent = 142 + AuditLogEventAutoModerationBlockMessage AuditLogEvent = 143 + AuditLogEventAutoModerationFlagToChannel AuditLogEvent = 144 + AuditLogEventAutoModerationUserCommunicationDis AuditLogEvent = 145 + + AuditLogEventCreatorMonetizationRequestCreated AuditLogEvent = 150 + AuditLogEventCreatorMonetizationTermsAccepted AuditLogEvent = 151 + + AuditLogEventOnboardingPromptCreate AuditLogEvent = 163 + AuditLogEventOnboardingPromptUpdate AuditLogEvent = 164 + AuditLogEventOnboardingPromptDelete AuditLogEvent = 165 + AuditLogEventOnboardingCreate AuditLogEvent = 166 + AuditLogEventOnboardingUpdate AuditLogEvent = 167 + + AuditLogEventHomeSettingsCreate AuditLogEvent = 190 + AuditLogEventHomeSettingsUpdate AuditLogEvent = 191 ) diff --git a/objects/auditlog/changekey.go b/objects/auditlog/changekey.go index 32969e2..a5b8fc7 100644 --- a/objects/auditlog/changekey.go +++ b/objects/auditlog/changekey.go @@ -63,4 +63,37 @@ const ( ChangeKeyEnableEmoticons ChangeKey = "enable_emoticons" ChangeKeyExpireBehaviour ChangeKey = "expire_behaviour" ChangeKeyExpireGracePeriod ChangeKey = "expire_grace_period" + + // guild + ChangeKeyDiscoverySplashHash ChangeKey = "discovery_splash_hash" + ChangeKeyBanner ChangeKey = "banner_hash" + ChangeKeyRulesChannelId ChangeKey = "rules_channel_id" + ChangeKeyPublicUpdatesChannelId ChangeKey = "public_updates_channel_id" + ChangeKeyPreferredLocale ChangeKey = "preferred_locale" + ChangeKeyPremiumProgressBarEnabled ChangeKey = "premium_progress_bar_enabled" + + // channel + ChangeKeyDefaultAutoArchiveDuration ChangeKey = "default_auto_archive_duration" + ChangeKeyForumTags ChangeKey = "available_tags" + ChangeKeyDefaultReactionEmoji ChangeKey = "default_reaction_emoji" + ChangeKeyDefaultSortOrder ChangeKey = "default_sort_order" + ChangeKeyDefaultForumLayout ChangeKey = "default_forum_layout" + + // role + ChangeKeyUnicodeEmoji ChangeKey = "unicode_emoji" + ChangeKeyIconEmoji ChangeKey = "icon_emoji" + + // thread + ChangeKeyArchived ChangeKey = "archived" + ChangeKeyAutoArchiveDuration ChangeKey = "auto_archive_duration" + ChangeKeyLocked ChangeKey = "locked" + + // soundboard + ChangeKeySoundId ChangeKey = "sound_id" + ChangeKeyVolume ChangeKey = "volume" + ChangeKeyEmojiName ChangeKey = "emoji_name" + ChangeKeyEmojiId ChangeKey = "emoji_id" + + // command permissions + ChangeKeyCommandId ChangeKey = "command_id" ) diff --git a/objects/auditlog/entitytype.go b/objects/auditlog/entitytype.go index 143249a..1ca5650 100644 --- a/objects/auditlog/entitytype.go +++ b/objects/auditlog/entitytype.go @@ -3,6 +3,6 @@ package auditlog type EntityType string const ( - EntityTypeMember EntityType = "member" - EntityTypeRole EntityType = "role" + EntityTypeRole EntityType = "0" + EntityTypeMember EntityType = "1" ) From def858b30a674e3ba03c92b3599d3df51c8780a3 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 18:02:20 +0100 Subject: [PATCH 34/73] Add owner team member role constant Introduce a new TeamMemberRole constant (TeamMemberRoleOwner = "owner") in objects/application/team.go to represent the owner role alongside admin, developer, and read_only. This enables explicit handling of owner-level team permissions. https://docs.discord.com/developers/topics/teams#team-member-roles --- objects/application/team.go | 1 + 1 file changed, 1 insertion(+) diff --git a/objects/application/team.go b/objects/application/team.go index 5c7b8d8..6265df4 100644 --- a/objects/application/team.go +++ b/objects/application/team.go @@ -27,6 +27,7 @@ const ( TeamMembershipStateInvited TeamMembershipState = 1 TeamMembershipStateAccepted TeamMembershipState = 2 + TeamMemberRoleOwner TeamMemberRole = "owner" TeamMemberRoleAdmin TeamMemberRole = "admin" TeamMemberRoleDeveloper TeamMemberRole = "developer" TeamMemberRoleReadOnly TeamMemberRole = "read_only" From f6b9fc86cbdfc0146b14105d0bbb6c02d5d56ea1 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 18:13:48 +0100 Subject: [PATCH 35/73] Extend Application with webhooks & integrations Add new fields to Application to support event webhooks and integration config: ApproximateUserInstallCount, EventWebhooksUrl, EventWebhooksStatus, EventWebhooksTypes, and IntegrationTypesConfig (map[ApplicationIntegrationType]ApplicationIntegrationTypeConfig). Introduce types ApplicationEventWebhookStatus, ApplicationIntegrationType and ApplicationIntegrationTypeConfig (with OAuth2InstallParams). Also adjust FlagApplicationCommandBadge bit from 1<<20 to 1<<23. These changes align the struct with added API fields for webhooks and integration install parameters. https://docs.discord.com/developers/resources/application --- objects/application/application.go | 78 +++++++++++++++++++----------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/objects/application/application.go b/objects/application/application.go index 92a14a1..7b3a1d5 100644 --- a/objects/application/application.go +++ b/objects/application/application.go @@ -6,32 +6,56 @@ import ( ) type Application struct { - Id uint64 `json:"id,string"` - Name string `json:"name"` - Icon *string `json:"icon"` - Description string `json:"description"` - RpcOrigins []string `json:"rpc_origins,omitempty"` - BotPublic bool `json:"bot_public"` - BotRequireCodeGrant bool `json:"bot_require_code_grant"` - Bot *user.User `json:"bot,omitempty"` - TermsOfServiceUrl *string `json:"terms_of_service_url,omitempty"` - PrivacyPolicyUrl *string `json:"privacy_policy_url,omitempty"` - Owner *user.User `json:"owner,omitempty"` - VerifyKey string `json:"verify_key"` - Team *Team `json:"team"` - GuildId *uint64 `json:"guild_id,string,omitempty"` - Guild *guild.Guild `json:"guild,omitempty"` - PrimarySkuId *uint64 `json:"primary_sku_id,string,omitempty"` - Slug *string `json:"slug,omitempty"` - CoverImage *string `json:"cover_image,omitempty"` - Flags *Flag `json:"flags,omitempty"` - ApproximateGuildCount *int `json:"approximate_guild_count,omitempty"` - RedirectUris []string `json:"redirect_uris,omitempty"` - InteractionsEndpointUrl *string `json:"interactions_endpoint_url,omitempty"` - RoleConnectionsVerificationUrl *string `json:"role_connections_verification_url,omitempty"` - Tags []string `json:"tags,omitempty"` - InstallParams *InstallParams `json:"install_params,omitempty"` - CustomInstallUrl *string `json:"custom_install_url,omitempty"` + Id uint64 `json:"id,string"` + Name string `json:"name"` + Icon *string `json:"icon"` + Description string `json:"description"` + RpcOrigins []string `json:"rpc_origins,omitempty"` + BotPublic bool `json:"bot_public"` + BotRequireCodeGrant bool `json:"bot_require_code_grant"` + Bot *user.User `json:"bot,omitempty"` + TermsOfServiceUrl *string `json:"terms_of_service_url,omitempty"` + PrivacyPolicyUrl *string `json:"privacy_policy_url,omitempty"` + Owner *user.User `json:"owner,omitempty"` + VerifyKey string `json:"verify_key"` + Team *Team `json:"team"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + Guild *guild.Guild `json:"guild,omitempty"` + PrimarySkuId *uint64 `json:"primary_sku_id,string,omitempty"` + Slug *string `json:"slug,omitempty"` + CoverImage *string `json:"cover_image,omitempty"` + Flags *Flag `json:"flags,omitempty"` + ApproximateGuildCount *int `json:"approximate_guild_count,omitempty"` + ApproximateUserInstallCount *int `json:"approximate_user_install_count,omitempty"` + RedirectUris []string `json:"redirect_uris,omitempty"` + InteractionsEndpointUrl *string `json:"interactions_endpoint_url,omitempty"` + RoleConnectionsVerificationUrl *string `json:"role_connections_verification_url,omitempty"` + EventWebhooksUrl *string `json:"event_webhooks_url,omitempty"` + EventWebhooksStatus ApplicationEventWebhookStatus `json:"event_webhooks_status,omitempty"` + EventWebhooksTypes []string `json:"event_webhooks_types,omitempty"` + Tags []string `json:"tags,omitempty"` + InstallParams *InstallParams `json:"install_params,omitempty"` + IntegrationTypesConfig map[ApplicationIntegrationType]ApplicationIntegrationTypeConfig `json:"integration_types_config,omitempty"` + CustomInstallUrl *string `json:"custom_install_url,omitempty"` +} + +type ApplicationEventWebhookStatus int + +const ( + ApplicationEventWebhookStatusDisabled ApplicationEventWebhookStatus = 1 + ApplicationEventWebhookStatusEnabled ApplicationEventWebhookStatus = 2 + ApplicationEventWebhookStatusDisabledByDiscord ApplicationEventWebhookStatus = 3 +) + +type ApplicationIntegrationType int + +const ( + ApplicationIntegrationTypeGuildInstall ApplicationIntegrationType = 0 + ApplicationIntegrationTypeUserInstall ApplicationIntegrationType = 1 +) + +type ApplicationIntegrationTypeConfig struct { + OAuth2InstallParams *InstallParams `json:"oauth2_install_params,omitempty"` } type Flag uint64 @@ -46,7 +70,7 @@ const ( FlagEmbedded Flag = 1 << 17 FlagGatewayMessageContent Flag = 1 << 18 FlagGatewayMessageContentLimited Flag = 1 << 19 - FlagApplicationCommandBadge Flag = 1 << 20 + FlagApplicationCommandBadge Flag = 1 << 23 ) func (f Flag) Has(flag Flag) bool { From 6bb55455621afe7082bc377ea4511bb9c237a1c8 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 18:41:54 +0100 Subject: [PATCH 36/73] Add localization, handler & integration types Update application command types to match new API fields: add name_localizations and description_localizations to ApplicationCommand, ApplicationCommandOption and option choices; add IntegrationTypes (using application.ApplicationIntegrationType) and a Handler field with a new ApplicationCommandHandlerType enum; add Type to ApplicationCommandInteractionDataOption. Also import the application package and adjust struct fields/order to accommodate these additions for improved localization and handler/integration support. https://docs.discord.com/developers/interactions/application-commands --- objects/interaction/applicationcommand.go | 35 +++++++++++++------ .../interaction/applicationcommandoption.go | 32 +++++++++-------- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/objects/interaction/applicationcommand.go b/objects/interaction/applicationcommand.go index 07c5f05..2f87192 100644 --- a/objects/interaction/applicationcommand.go +++ b/objects/interaction/applicationcommand.go @@ -1,17 +1,23 @@ package interaction +import "github.com/TicketsBot-cloud/gdl/objects/application" + type ApplicationCommand struct { - Id uint64 `json:"id,string,omitempty"` - Type ApplicationCommandType `json:"type"` - ApplicationId uint64 `json:"application_id,string,omitempty"` - GuildId *uint64 `json:"guild_id,string,omitempty"` - Name string `json:"name"` - Description string `json:"description"` - Options []ApplicationCommandOption `json:"options,omitempty"` - DefaultMemberPermissions *string `json:"default_member_permissions,omitempty"` - Nsfw bool `json:"nsfw,omitempty"` - Version uint64 `json:"version,string,omitempty"` - Contexts []InteractionContextType `json:"contexts,omitempty"` + Id uint64 `json:"id,string,omitempty"` + Type ApplicationCommandType `json:"type"` + ApplicationId uint64 `json:"application_id,string,omitempty"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + Name string `json:"name"` + NameLocalizations map[string]string `json:"name_localizations,omitempty"` + Description string `json:"description"` + DescriptionLocalizations map[string]string `json:"description_localizations,omitempty"` + Options []ApplicationCommandOption `json:"options,omitempty"` + DefaultMemberPermissions *string `json:"default_member_permissions,omitempty"` + Nsfw bool `json:"nsfw,omitempty"` + IntegrationTypes []application.ApplicationIntegrationType `json:"integration_types,omitempty"` + Contexts []InteractionContextType `json:"contexts,omitempty"` + Version uint64 `json:"version,string,omitempty"` + Handler *ApplicationCommandHandlerType `json:"handler,omitempty"` } type ApplicationCommandType uint8 @@ -22,3 +28,10 @@ const ( ApplicationCommandTypeMessage ApplicationCommandTypePrimaryEntryPoint ) + +type ApplicationCommandHandlerType uint8 + +const ( + ApplicationCommandHandlerTypeAppHandler ApplicationCommandHandlerType = 1 + ApplicationCommandHandlerTypeDiscordLaunchActivity ApplicationCommandHandlerType = 2 +) diff --git a/objects/interaction/applicationcommandoption.go b/objects/interaction/applicationcommandoption.go index e6fbfd1..4ca01b8 100644 --- a/objects/interaction/applicationcommandoption.go +++ b/objects/interaction/applicationcommandoption.go @@ -3,6 +3,7 @@ package interaction import "github.com/TicketsBot-cloud/gdl/objects/channel" type ApplicationCommandInteractionDataOption struct { + Type ApplicationCommandOptionType `json:"type"` Name string `json:"name"` Value interface{} `json:"value,omitempty"` Options []ApplicationCommandInteractionDataOption `json:"options,omitempty"` @@ -10,18 +11,20 @@ type ApplicationCommandInteractionDataOption struct { } type ApplicationCommandOption struct { - Type ApplicationCommandOptionType `json:"type"` - Name string `json:"name"` - Description string `json:"description"` - Required bool `json:"required,omitempty"` - Choices []ApplicationCommandOptionChoice `json:"choices,omitempty"` - Autocomplete bool `json:"autocomplete,omitempty"` - Options []ApplicationCommandOption `json:"options,omitempty"` - ChannelTypes []channel.ChannelType `json:"channel_types,omitempty"` - MinValue *float64 `json:"min_value,omitempty"` - MaxValue *float64 `json:"max_value,omitempty"` - MinLength *int `json:"min_length,omitempty"` - MaxLength *int `json:"max_length,omitempty"` + Type ApplicationCommandOptionType `json:"type"` + Name string `json:"name"` + NameLocalizations map[string]string `json:"name_localizations,omitempty"` + Description string `json:"description"` + DescriptionLocalizations map[string]string `json:"description_localizations,omitempty"` + Required bool `json:"required,omitempty"` + Choices []ApplicationCommandOptionChoice `json:"choices,omitempty"` + Autocomplete bool `json:"autocomplete,omitempty"` + Options []ApplicationCommandOption `json:"options,omitempty"` + ChannelTypes []channel.ChannelType `json:"channel_types,omitempty"` + MinValue *float64 `json:"min_value,omitempty"` + MaxValue *float64 `json:"max_value,omitempty"` + MinLength *int `json:"min_length,omitempty"` + MaxLength *int `json:"max_length,omitempty"` } type ApplicationCommandOptionType uint8 @@ -41,6 +44,7 @@ const ( ) type ApplicationCommandOptionChoice struct { - Name string `json:"name"` - Value interface{} `json:"value"` // string, int or double + Name string `json:"name"` + NameLocalizations map[string]string `json:"name_localizations,omitempty"` + Value interface{} `json:"value"` // string, int or double } From a7619350cb214f46270e4d584a765f4405785106 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 19:10:04 +0100 Subject: [PATCH 37/73] Rename explicit content filter constants Rename constants in the guild package to exported, Go-style names while keeping their values and type (ExplicitContentFilterLevel). DISABLED, MEMBERS_WITHOUT_ROLES and ALL_MEMBERS are changed to ExplicitContentFilterLevelDisabled, ExplicitContentFilterLevelMembersWithoutRoles and ExplicitContentFilterLevelAllMembers respectively to improve clarity and naming consistency. https://docs.discord.com/developers/resources/guild#guild-object-explicit-content-filter-level --- objects/guild/explicitcontentfilterlevel.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/objects/guild/explicitcontentfilterlevel.go b/objects/guild/explicitcontentfilterlevel.go index c4c81b0..07e7138 100644 --- a/objects/guild/explicitcontentfilterlevel.go +++ b/objects/guild/explicitcontentfilterlevel.go @@ -3,7 +3,7 @@ package guild type ExplicitContentFilterLevel int const ( - DISABLED ExplicitContentFilterLevel = 0 - MEMBERS_WITHOUT_ROLES ExplicitContentFilterLevel = 1 - ALL_MEMBERS ExplicitContentFilterLevel = 2 + ExplicitContentFilterLevelDisabled ExplicitContentFilterLevel = 0 + ExplicitContentFilterLevelMembersWithoutRoles ExplicitContentFilterLevel = 1 + ExplicitContentFilterLevelAllMembers ExplicitContentFilterLevel = 2 ) From 39db06f3700347ab3c911f8e1a8c4d38c824acbe Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 19:11:26 +0100 Subject: [PATCH 38/73] Rename VerificationLevel constants Rename constants NONE/LOW/MEDIUM/HIGH/VERY_HIGH to VerificationLevelNone/Low/Medium/High/VeryHigh. Values are unchanged; this clarifies names, avoids global identifier collisions and aligns with Go naming/export conventions. https://docs.discord.com/developers/resources/guild#guild-object-verification-level --- objects/guild/verificationlevel.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/objects/guild/verificationlevel.go b/objects/guild/verificationlevel.go index 4216ed7..5fab283 100644 --- a/objects/guild/verificationlevel.go +++ b/objects/guild/verificationlevel.go @@ -3,9 +3,9 @@ package guild type VerificationLevel int const ( - NONE VerificationLevel = 0 - LOW VerificationLevel = 1 - MEDIUM VerificationLevel = 2 - HIGH VerificationLevel = 3 - VERY_HIGH VerificationLevel = 4 + VerificationLevelNone VerificationLevel = 0 + VerificationLevelLow VerificationLevel = 1 + VerificationLevelMedium VerificationLevel = 2 + VerificationLevelHigh VerificationLevel = 3 + VerificationLevelVeryHigh VerificationLevel = 4 ) From a74e0a890fd04c17cdf65c3c814346d5280cdf2a Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 19:24:27 +0100 Subject: [PATCH 39/73] Rename permission overwrite constants Rename PermissionTypeRole/PermissionTypeMember to PermissionOverwriteTypeRole/PermissionOverwriteTypeMember and assign explicit values (0/1) in objects/channel/permissionoverwritetype.go. Update permission checks in permission/permissioncalculator.go to use the new constant names. This clarifies the naming and keeps usages consistent across the codebase. --- objects/channel/permissionoverwritetype.go | 4 ++-- permission/permissioncalculator.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/objects/channel/permissionoverwritetype.go b/objects/channel/permissionoverwritetype.go index c6a4e3a..1be56a3 100644 --- a/objects/channel/permissionoverwritetype.go +++ b/objects/channel/permissionoverwritetype.go @@ -3,6 +3,6 @@ package channel type PermissionOverwriteType int const ( - PermissionTypeRole PermissionOverwriteType = iota - PermissionTypeMember + PermissionOverwriteTypeRole PermissionOverwriteType = 0 + PermissionOverwriteTypeMember PermissionOverwriteType = 1 ) diff --git a/permission/permissioncalculator.go b/permission/permissioncalculator.go index 2330a12..52e2cbc 100644 --- a/permission/permissioncalculator.go +++ b/permission/permissioncalculator.go @@ -146,7 +146,7 @@ func GetChannelMemberPermissions(ctx context.Context, shard *gateway.Shard, user } for _, overwrite := range ch.PermissionOverwrites { - if overwrite.Type == channel.PermissionTypeMember && overwrite.Id == userId { + if overwrite.Type == channel.PermissionOverwriteTypeMember && overwrite.Id == userId { initialPermissions &= ^overwrite.Deny initialPermissions |= overwrite.Allow } @@ -177,7 +177,7 @@ func GetChannelTotalRolePermissions(ctx context.Context, shard *gateway.Shard, g for _, role := range roles { if memberRole == role.Id { for _, overwrite := range ch.PermissionOverwrites { - if overwrite.Type == channel.PermissionTypeRole && overwrite.Id == role.Id { + if overwrite.Type == channel.PermissionOverwriteTypeRole && overwrite.Id == role.Id { allow |= overwrite.Allow deny |= overwrite.Deny break @@ -217,7 +217,7 @@ func GetChannelBasePermissions(ctx context.Context, shard *gateway.Shard, guildI } for _, overwrite := range ch.PermissionOverwrites { - if overwrite.Type == channel.PermissionTypeRole && overwrite.Id == publicRole.Id { + if overwrite.Type == channel.PermissionOverwriteTypeRole && overwrite.Id == publicRole.Id { initialPermissions &= ^overwrite.Deny initialPermissions |= overwrite.Allow break From 5f4365e85f7e919a82991323640994d93264ce78 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 19:27:55 +0100 Subject: [PATCH 40/73] Rename message activity constants and set values Rename constants in objects/channel/message/messageactivitytype.go to include 'Type' in their names and assign explicit integer values instead of using iota. This makes the values match the protocol/upstream activity type IDs (MessageActivityTypeJoin=1, Spectate=2, Listen=3, JoinRequest=5) and avoids a zero-valued enum. https://docs.discord.com/developers/resources/message#message-object-message-activity-structure --- objects/channel/message/messageactivitytype.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/objects/channel/message/messageactivitytype.go b/objects/channel/message/messageactivitytype.go index d1645b0..d414092 100644 --- a/objects/channel/message/messageactivitytype.go +++ b/objects/channel/message/messageactivitytype.go @@ -3,8 +3,8 @@ package message type MessageActivityType int const ( - MessageActivityJoin MessageActivityType = iota - MessageActivitySpectate - MessageActivityListen - MessageActivityJoinRequest + MessageActivityTypeJoin MessageActivityType = 1 + MessageActivityTypeSpectate MessageActivityType = 2 + MessageActivityTypeListen MessageActivityType = 3 + MessageActivityTypeJoinRequest MessageActivityType = 5 ) From 9b024fc5766aa2469fc441c8bd472741f922738a Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 19:32:18 +0100 Subject: [PATCH 41/73] Update channel type enums and usages Replace iota-based ChannelType declarations with explicit numeric values and rename constants to match updated Discord channel type names (e.g. GuildNews -> Announcement, GuildNewsThread -> AnnouncementThread, GuildPublicThread -> PublicThread, GuildPrivateThread -> PrivateThread). Add new/adjusted types (including GuildMedia) and normalize enum values. Update gateway/restwrapper.go to use ChannelTypePublicThread and ChannelTypePrivateThread when starting threads. Affects objects/channel/channeltype.go and gateway/restwrapper.go. https://docs.discord.com/developers/resources/channel#channel-object-channel-types --- gateway/restwrapper.go | 4 ++-- objects/channel/channeltype.go | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/gateway/restwrapper.go b/gateway/restwrapper.go index 41f9bae..248526a 100644 --- a/gateway/restwrapper.go +++ b/gateway/restwrapper.go @@ -218,7 +218,7 @@ func (s *Shard) CreatePublicThread(ctx context.Context, channelId uint64, name s data := rest.StartThreadWithoutMessageData{ Name: name, AutoArchiveDuration: autoArchiveDuration, - Type: channel.ChannelTypeGuildPublicThread, + Type: channel.ChannelTypePublicThread, } return rest.StartThreadWithoutMessage(ctx, s.Token, s.ShardManager.RateLimiter, channelId, data) @@ -228,7 +228,7 @@ func (s *Shard) CreatePrivateThread(ctx context.Context, channelId uint64, name data := rest.StartThreadWithoutMessageData{ Name: name, AutoArchiveDuration: autoArchiveDuration, - Type: channel.ChannelTypeGuildPrivateThread, + Type: channel.ChannelTypePrivateThread, Invitable: invitable, } diff --git a/objects/channel/channeltype.go b/objects/channel/channeltype.go index 82d6ec6..9074627 100644 --- a/objects/channel/channeltype.go +++ b/objects/channel/channeltype.go @@ -3,17 +3,17 @@ package channel type ChannelType int const ( - ChannelTypeGuildText ChannelType = iota - ChannelTypeDM - ChannelTypeGuildVoice - ChannelTypeGroupDM - ChannelTypeGuildCategory - ChannelTypeGuildNews - ChannelTypeGuildStore - ChannelTypeGuildNewsThread ChannelType = iota + 3 - ChannelTypeGuildPublicThread - ChannelTypeGuildPrivateThread - ChannelTypeGuildStageVoice - ChannelTypeGuildDirectory - ChannelTypeGuildForum + ChannelTypeGuildText ChannelType = 0 + ChannelTypeDM ChannelType = 1 + ChannelTypeGuildVoice ChannelType = 2 + ChannelTypeGroupDM ChannelType = 3 + ChannelTypeGuildCategory ChannelType = 4 + ChannelTypeGuildAnnouncement ChannelType = 5 + ChannelTypeAnnouncementThread ChannelType = 10 + ChannelTypePublicThread ChannelType = 11 + ChannelTypePrivateThread ChannelType = 12 + ChannelTypeGuildStageVoice ChannelType = 13 + ChannelTypeGuildDirectory ChannelType = 14 + ChannelTypeGuildForum ChannelType = 15 + ChannelTypeGuildMedia ChannelType = 16 ) From 5a51b44cad51babcebdd6a3b7ab37f47e86f2e6d Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 19:34:15 +0100 Subject: [PATCH 42/73] Fix typo in DefaultMessageNotificationLevel Correct a spelling mistake in the DefaultMessageNotificationLevel constant name: DefaultMessageNotificationLevelOnlyMengions -> DefaultMessageNotificationLevelOnlyMentions. This is a non-functional rename to fix the identifier and improve code clarity. https://docs.discord.com/developers/resources/guild#guild-object-default-message-notification-level --- objects/guild/defaultmessagenotificationlevel.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objects/guild/defaultmessagenotificationlevel.go b/objects/guild/defaultmessagenotificationlevel.go index aff300c..3a17d1a 100644 --- a/objects/guild/defaultmessagenotificationlevel.go +++ b/objects/guild/defaultmessagenotificationlevel.go @@ -4,5 +4,5 @@ type DefaultMessageNotificationLevel int const ( DefaultMessageNotificationLevelAllMessages DefaultMessageNotificationLevel = 0 - DefaultMessageNotificationLevelOnlyMengions DefaultMessageNotificationLevel = 1 + DefaultMessageNotificationLevelOnlyMentions DefaultMessageNotificationLevel = 1 ) From e48f090f109a4c379788b8eba99b5e8b6f29c930 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 19:40:44 +0100 Subject: [PATCH 43/73] Add ID to ActionRow and fix marshaled type Add an optional Id field to ActionRow and ensure Components has the proper json key. Fix MarshalJSON to emit ComponentActionRow (was incorrectly ComponentButton), preventing the row from being marshaled as a button. Minor formatting cleanup in BuildActionRow. https://docs.discord.com/developers/components/reference#action-row --- objects/interaction/component/componentactionrow.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/objects/interaction/component/componentactionrow.go b/objects/interaction/component/componentactionrow.go index 2b1ef5f..4959a6f 100644 --- a/objects/interaction/component/componentactionrow.go +++ b/objects/interaction/component/componentactionrow.go @@ -3,7 +3,8 @@ package component import "encoding/json" type ActionRow struct { - Components []Component + Id *int `json:"id,omitempty"` + Components []Component `json:"components"` } func (a ActionRow) Type() ComponentType { @@ -17,14 +18,14 @@ func (a ActionRow) MarshalJSON() ([]byte, error) { Type ComponentType `json:"type"` WrappedActionRow }{ - Type: ComponentButton, + Type: ComponentActionRow, WrappedActionRow: WrappedActionRow(a), }) } func BuildActionRow(components ...Component) Component { return Component{ - Type: ComponentActionRow, + Type: ComponentActionRow, ComponentData: ActionRow{ Components: components, }, From e0ab77f61dc32e3c3482330b9dbb55f02f8d22d4 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 19:51:22 +0100 Subject: [PATCH 44/73] Make interaction fields optional and add new metadata Update interaction types to better handle optional/absent JSON fields and add new metadata. InteractionMetadata: make Locale and GuildLocale pointer types with omitempty, add AuthorizingIntegrationOwners, Context, and AttachmentSizeLimit. ApplicationCommandInteractionData: make Resolved a pointer (omitempty), make Options optional, add GuildId and make TargetId a pointer (omitempty). ResolvedData: add omitempty to all resolved maps. These changes allow proper unmarshalling of partial payloads and support additional API fields. https://docs.discord.com/developers/interactions/receiving-and-responding#interactions --- objects/interaction/interaction.go | 34 +++++++++++++++++------------- objects/interaction/resolved.go | 12 +++++------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/objects/interaction/interaction.go b/objects/interaction/interaction.go index 77e169e..df87d8f 100644 --- a/objects/interaction/interaction.go +++ b/objects/interaction/interaction.go @@ -19,18 +19,21 @@ type Interaction struct { type InteractionMetadata struct { Interaction - Id uint64 `json:"id,string"` - ApplicationId uint64 `json:"application_id,string"` - GuildId objects.NullableSnowflake `json:"guild_id"` - ChannelId uint64 `json:"channel_id,string"` - Channel channel.PartialChannel `json:"channel"` - Member *member.Member `json:"member"` - User *user.User `json:"user"` - Token string `json:"token"` - AppPermissions uint64 `json:"app_permissions,string"` - Locale string `json:"locale"` - GuildLocale string `json:"guild_locale"` - Entitlements []entitlement.Entitlement `json:"entitlements"` + Id uint64 `json:"id,string"` + ApplicationId uint64 `json:"application_id,string"` + GuildId objects.NullableSnowflake `json:"guild_id"` + ChannelId uint64 `json:"channel_id,string"` + Channel channel.PartialChannel `json:"channel"` + Member *member.Member `json:"member"` + User *user.User `json:"user"` + Token string `json:"token"` + AppPermissions uint64 `json:"app_permissions,string"` + Locale *string `json:"locale,omitempty"` + GuildLocale *string `json:"guild_locale,omitempty"` + Entitlements []entitlement.Entitlement `json:"entitlements"` + AuthorizingIntegrationOwners map[string]string `json:"authorizing_integration_owners"` + Context *InteractionContextType `json:"context,omitempty"` + AttachmentSizeLimit int `json:"attachment_size_limit"` } type InteractionType uint8 @@ -58,9 +61,10 @@ type ApplicationCommandInteractionData struct { Id uint64 `json:"id,string"` Name string `json:"name"` Type ApplicationCommandType `json:"type"` - Resolved ResolvedData `json:"resolved"` - Options []ApplicationCommandInteractionDataOption `json:"options"` - TargetId uint64 `json:"target_id,string"` + Resolved *ResolvedData `json:"resolved,omitempty"` + Options []ApplicationCommandInteractionDataOption `json:"options,omitempty"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + TargetId *uint64 `json:"target_id,string,omitempty"` } type MessageComponentInteraction struct { diff --git a/objects/interaction/resolved.go b/objects/interaction/resolved.go index c2c5926..62d2746 100644 --- a/objects/interaction/resolved.go +++ b/objects/interaction/resolved.go @@ -10,10 +10,10 @@ import ( ) type ResolvedData struct { - Users map[objects.Snowflake]user.User `json:"users"` - Members map[objects.Snowflake]member.Member `json:"members"` - Roles map[objects.Snowflake]guild.Role `json:"roles"` - Channels map[objects.Snowflake]channel.Channel `json:"channels"` - Messages map[objects.Snowflake]message.Message `json:"messages"` - Attachments map[objects.Snowflake]channel.Attachment `json:"attachments"` + Users map[objects.Snowflake]user.User `json:"users,omitempty"` + Members map[objects.Snowflake]member.Member `json:"members,omitempty"` + Roles map[objects.Snowflake]guild.Role `json:"roles,omitempty"` + Channels map[objects.Snowflake]channel.Channel `json:"channels,omitempty"` + Messages map[objects.Snowflake]message.Message `json:"messages,omitempty"` + Attachments map[objects.Snowflake]channel.Attachment `json:"attachments,omitempty"` } From e3860a60b4e9489e125b457dc1532b5e008f61e2 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 20:41:02 +0100 Subject: [PATCH 45/73] Remove Vip field from VoiceRegion struct Delete the unused `Vip` boolean field from the VoiceRegion struct in objects/guild/voiceregion.go to match the updated model/schema. Cleans up the struct by removing an obsolete field. https://docs.discord.com/developers/resources/voice#voice-region-object --- objects/guild/voiceregion.go | 1 - 1 file changed, 1 deletion(-) diff --git a/objects/guild/voiceregion.go b/objects/guild/voiceregion.go index 3bf8c78..7995fd0 100644 --- a/objects/guild/voiceregion.go +++ b/objects/guild/voiceregion.go @@ -3,7 +3,6 @@ package guild type VoiceRegion struct { Id string `json:"id"` Name string `json:"name"` - Vip bool `json:"vip"` Optimal bool `json:"optimal"` Deprecated bool `json:"deprecated"` Custom bool `json:"custom"` From 500af0754194c68a4f0b49a4837aace7ea8adc08 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 20:50:29 +0100 Subject: [PATCH 46/73] Reorder ClientStatusType constants Swap the declaration order of ClientStatusTypeIdle and ClientStatusTypeDoNotDisturb in objects/user/clientstatustype.go. This only adjusts the order of constant declarations and does not change their values or behavior. https://docs.discord.com/developers/events/gateway-events#update-presence --- objects/user/clientstatustype.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objects/user/clientstatustype.go b/objects/user/clientstatustype.go index 105c016..356b947 100644 --- a/objects/user/clientstatustype.go +++ b/objects/user/clientstatustype.go @@ -4,8 +4,8 @@ type ClientStatusType string const ( ClientStatusTypeOnline ClientStatusType = "online" - ClientStatusTypeIdle ClientStatusType = "idle" ClientStatusTypeDoNotDisturb ClientStatusType = "dnd" + ClientStatusTypeIdle ClientStatusType = "idle" ClientStatusTypeInvisible ClientStatusType = "invisible" ClientStatusTypeOffline ClientStatusType = "offline" ) From 62648f40d8798591597d1e596006196ebd10f7fc Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 22:01:45 +0100 Subject: [PATCH 47/73] Add cover and URL fields to user Asset struct Extend the user.Asset struct with InviteCoverImage, LargeUrl, and SmallUrl to support an invite cover image and explicit image URLs for large and small assets. Existing fields and JSON tags are preserved and marked omitempty for backward compatibility. https://docs.discord.com/developers/events/gateway-events#activity-object-activity-assets --- objects/user/asset.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/objects/user/asset.go b/objects/user/asset.go index 9b96f6e..df648cb 100644 --- a/objects/user/asset.go +++ b/objects/user/asset.go @@ -1,8 +1,11 @@ package user type Asset struct { - LargeImage string `json:"large_image,omitempty"` - LargeText string `json:"large_text,omitempty"` - SmallImage string `json:"small_image,omitempty"` - SmallText string `json:"small_text,omitempty"` + InviteCoverImage string `json:"invite_cover_image,omitempty"` + LargeImage string `json:"large_image,omitempty"` + LargeText string `json:"large_text,omitempty"` + LargeUrl string `json:"large_url,omitempty"` + SmallImage string `json:"small_image,omitempty"` + SmallText string `json:"small_text,omitempty"` + SmallUrl string `json:"small_url,omitempty"` } From 0898c19fed56c5b75940536355e750e4a033a9b1 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 22:07:19 +0100 Subject: [PATCH 48/73] Add optional ID field to Container struct Add an optional Id field to the Container struct (Id *int `json:"id,omitempty"`) so component containers can include an "id" during JSON serialization. This enables identifying/tracking individual containers in interaction payloads. https://docs.discord.com/developers/components/reference#container --- objects/interaction/component/component_container.go | 1 + 1 file changed, 1 insertion(+) diff --git a/objects/interaction/component/component_container.go b/objects/interaction/component/component_container.go index d88405f..5c97478 100644 --- a/objects/interaction/component/component_container.go +++ b/objects/interaction/component/component_container.go @@ -5,6 +5,7 @@ import ( ) type Container struct { + Id *int `json:"id,omitempty"` Components []Component `json:"components"` AccentColor *int `json:"accent_color,omitempty"` Spoiler *bool `json:"spoiler,omitempty"` From 2f48d0d7d489fd9632787543eb599915c18a2e20 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 22:32:01 +0100 Subject: [PATCH 49/73] Update interaction component structs for new schema Align component objects with the updated API schema: add optional Id fields across many component types, introduce SelectDefaultValue and related types to support default selections (DefaultValues) on select components, add ChannelTypes to ChannelSelect and import channel package, make many fields optional (add `omitempty`) for accurate JSON marshaling, change UnfurledMediaItem fields to optional pointers and require Media where appropriate, and adjust other component fields (Label, Button, InputText, etc.) to match the new shape. These changes enable component IDs, default selected values, improved optional handling, and better compatibility with the upstream component model. https://docs.discord.com/developers/components/reference --- .../component/component_channel_select.go | 22 +++++++++++-------- .../component/component_checkbox.go | 7 ++++-- .../component/component_checkbox_group.go | 11 +++++----- .../interaction/component/component_file.go | 1 + .../component/component_file_upload.go | 1 + .../interaction/component/component_label.go | 3 ++- .../component/component_media_gallery.go | 3 ++- .../component/component_mentionable_select.go | 15 +++++++------ .../component/component_radio_group.go | 1 + .../component/component_role_select.go | 15 +++++++------ .../component/component_section.go | 3 ++- .../component/component_separator.go | 1 + .../component/component_text_display.go | 1 + .../component/component_thumbnail.go | 13 ++++++----- .../component/component_user_select.go | 14 +++++++----- .../interaction/component/componentbutton.go | 5 +++-- objects/interaction/component/inputtext.go | 1 + objects/interaction/component/selectmenu.go | 18 +++++++++++++-- 18 files changed, 86 insertions(+), 49 deletions(-) diff --git a/objects/interaction/component/component_channel_select.go b/objects/interaction/component/component_channel_select.go index 61a2814..9778ea9 100644 --- a/objects/interaction/component/component_channel_select.go +++ b/objects/interaction/component/component_channel_select.go @@ -2,18 +2,22 @@ package component import ( "encoding/json" + + "github.com/TicketsBot-cloud/gdl/objects/channel" ) type ChannelSelect struct { - CustomId string `json:"custom_id"` - Options []SelectOption `json:"options"` - Placeholder string `json:"placeholder,omitempty"` - MinValues *int `json:"min_values,omitempty"` - MaxValues *int `json:"max_values,omitempty"` - Disabled *bool `json:"disabled"` - Required *bool `json:"required,omitempty"` -} - + Id *int `json:"id,omitempty"` + CustomId string `json:"custom_id"` + ChannelTypes []channel.ChannelType `json:"channel_types,omitempty"` + Placeholder string `json:"placeholder,omitempty"` + DefaultValues []SelectDefaultValue `json:"default_values,omitempty"` + MinValues *int `json:"min_values,omitempty"` + MaxValues *int `json:"max_values,omitempty"` + Disabled *bool `json:"disabled,omitempty"` + Required *bool `json:"required,omitempty"` +} + func (i ChannelSelect) Type() ComponentType { return ComponentChannelSelect } diff --git a/objects/interaction/component/component_checkbox.go b/objects/interaction/component/component_checkbox.go index 6e3ec76..80a5b58 100644 --- a/objects/interaction/component/component_checkbox.go +++ b/objects/interaction/component/component_checkbox.go @@ -3,8 +3,11 @@ package component import "encoding/json" type Checkbox struct { - CustomId string `json:"custom_id"` - Default bool `json:"default,omitempty"` + Id *int `json:"id,omitempty"` + CustomId string `json:"custom_id"` + Label string `json:"label"` + Description *string `json:"description,omitempty"` + Default bool `json:"default,omitempty"` } func (c Checkbox) Type() ComponentType { diff --git a/objects/interaction/component/component_checkbox_group.go b/objects/interaction/component/component_checkbox_group.go index 156a11f..6e21519 100644 --- a/objects/interaction/component/component_checkbox_group.go +++ b/objects/interaction/component/component_checkbox_group.go @@ -3,11 +3,12 @@ package component import "encoding/json" type CheckboxGroup struct { - CustomId string `json:"custom_id"` - Options []CheckboxGroupOption `json:"options"` - MinValues *int `json:"min_values,omitempty"` - MaxValues *int `json:"max_values,omitempty"` - Required *bool `json:"required,omitempty"` + Id *int `json:"id,omitempty"` + CustomId string `json:"custom_id"` + Options []CheckboxGroupOption `json:"options"` + MinValues *int `json:"min_values,omitempty"` + MaxValues *int `json:"max_values,omitempty"` + Required *bool `json:"required,omitempty"` } type CheckboxGroupOption struct { diff --git a/objects/interaction/component/component_file.go b/objects/interaction/component/component_file.go index 9196741..35454d4 100644 --- a/objects/interaction/component/component_file.go +++ b/objects/interaction/component/component_file.go @@ -5,6 +5,7 @@ import ( ) type File struct { + Id *int `json:"id,omitempty"` File UnfurledMediaItem `json:"file"` Spoiler *bool `json:"spoiler,omitempty"` } diff --git a/objects/interaction/component/component_file_upload.go b/objects/interaction/component/component_file_upload.go index fa164cd..3f5da32 100644 --- a/objects/interaction/component/component_file_upload.go +++ b/objects/interaction/component/component_file_upload.go @@ -3,6 +3,7 @@ package component import "encoding/json" type FileUpload struct { + Id *int `json:"id,omitempty"` CustomId string `json:"custom_id"` MinValues *int `json:"min_values,omitempty"` MaxValues *int `json:"max_values,omitempty"` diff --git a/objects/interaction/component/component_label.go b/objects/interaction/component/component_label.go index ccd15c0..d0a3f33 100644 --- a/objects/interaction/component/component_label.go +++ b/objects/interaction/component/component_label.go @@ -5,9 +5,10 @@ import ( ) type Label struct { + Id *int `json:"id,omitempty"` Label string `json:"label"` Description *string `json:"description,omitempty"` - Component Component `json:"component"` // This can only be string select or text input + Component Component `json:"component"` } func (i Label) Type() ComponentType { diff --git a/objects/interaction/component/component_media_gallery.go b/objects/interaction/component/component_media_gallery.go index 25a99b7..6fc8108 100644 --- a/objects/interaction/component/component_media_gallery.go +++ b/objects/interaction/component/component_media_gallery.go @@ -5,11 +5,12 @@ import ( ) type MediaGallery struct { + Id *int `json:"id,omitempty"` Items []MediaGalleryItem `json:"items"` } type MediaGalleryItem struct { - Media UnfurledMediaItem `json:"media,omitempty"` + Media UnfurledMediaItem `json:"media"` Description *string `json:"description,omitempty"` Spoiler *bool `json:"spoiler,omitempty"` } diff --git a/objects/interaction/component/component_mentionable_select.go b/objects/interaction/component/component_mentionable_select.go index 0d910bc..3a6f404 100644 --- a/objects/interaction/component/component_mentionable_select.go +++ b/objects/interaction/component/component_mentionable_select.go @@ -5,13 +5,14 @@ import ( ) type MentionableSelect struct { - CustomId string `json:"custom_id"` - Options []SelectOption `json:"options"` - Placeholder string `json:"placeholder,omitempty"` - MinValues *int `json:"min_values,omitempty"` - MaxValues *int `json:"max_values,omitempty"` - Disabled *bool `json:"disabled"` - Required *bool `json:"required,omitempty"` + Id *int `json:"id,omitempty"` + CustomId string `json:"custom_id"` + Placeholder string `json:"placeholder,omitempty"` + DefaultValues []SelectDefaultValue `json:"default_values,omitempty"` + MinValues *int `json:"min_values,omitempty"` + MaxValues *int `json:"max_values,omitempty"` + Disabled *bool `json:"disabled,omitempty"` + Required *bool `json:"required,omitempty"` } func (i MentionableSelect) Type() ComponentType { diff --git a/objects/interaction/component/component_radio_group.go b/objects/interaction/component/component_radio_group.go index 7461cd6..a35f92a 100644 --- a/objects/interaction/component/component_radio_group.go +++ b/objects/interaction/component/component_radio_group.go @@ -3,6 +3,7 @@ package component import "encoding/json" type RadioGroup struct { + Id *int `json:"id,omitempty"` CustomId string `json:"custom_id"` Options []RadioGroupOption `json:"options"` Required *bool `json:"required,omitempty"` diff --git a/objects/interaction/component/component_role_select.go b/objects/interaction/component/component_role_select.go index 5e0a2d7..1dd6b91 100644 --- a/objects/interaction/component/component_role_select.go +++ b/objects/interaction/component/component_role_select.go @@ -5,13 +5,14 @@ import ( ) type RoleSelect struct { - CustomId string `json:"custom_id"` - Options []SelectOption `json:"options"` - Placeholder string `json:"placeholder,omitempty"` - MinValues *int `json:"min_values,omitempty"` - MaxValues *int `json:"max_values,omitempty"` - Disabled *bool `json:"disabled"` - Required *bool `json:"required,omitempty"` + Id *int `json:"id,omitempty"` + CustomId string `json:"custom_id"` + Placeholder string `json:"placeholder,omitempty"` + DefaultValues []SelectDefaultValue `json:"default_values,omitempty"` + MinValues *int `json:"min_values,omitempty"` + MaxValues *int `json:"max_values,omitempty"` + Disabled *bool `json:"disabled,omitempty"` + Required *bool `json:"required,omitempty"` } func (i RoleSelect) Type() ComponentType { diff --git a/objects/interaction/component/component_section.go b/objects/interaction/component/component_section.go index 2fea6d4..43187ed 100644 --- a/objects/interaction/component/component_section.go +++ b/objects/interaction/component/component_section.go @@ -5,8 +5,9 @@ import ( ) type Section struct { + Id *int `json:"id,omitempty"` Components []Component `json:"components"` - Accessory Component `json:"accessory,omitempty"` + Accessory Component `json:"accessory"` } func (i Section) Type() ComponentType { diff --git a/objects/interaction/component/component_separator.go b/objects/interaction/component/component_separator.go index 40b9d20..7b3553d 100644 --- a/objects/interaction/component/component_separator.go +++ b/objects/interaction/component/component_separator.go @@ -5,6 +5,7 @@ import ( ) type Separator struct { + Id *int `json:"id,omitempty"` Divider *bool `json:"divider,omitempty"` Spacing *int `json:"spacing,omitempty"` } diff --git a/objects/interaction/component/component_text_display.go b/objects/interaction/component/component_text_display.go index f1cd1ef..45a61dc 100644 --- a/objects/interaction/component/component_text_display.go +++ b/objects/interaction/component/component_text_display.go @@ -5,6 +5,7 @@ import ( ) type TextDisplay struct { + Id *int `json:"id,omitempty"` Content string `json:"content"` } diff --git a/objects/interaction/component/component_thumbnail.go b/objects/interaction/component/component_thumbnail.go index 84ca046..bc526b5 100644 --- a/objects/interaction/component/component_thumbnail.go +++ b/objects/interaction/component/component_thumbnail.go @@ -5,17 +5,18 @@ import ( ) type Thumbnail struct { - Media UnfurledMediaItem `json:"media,omitempty"` + Id *int `json:"id,omitempty"` + Media UnfurledMediaItem `json:"media"` Description *string `json:"description,omitempty"` Spoiler *bool `json:"spoiler,omitempty"` } type UnfurledMediaItem struct { - Url string `json:"url"` - ProxyUrl string `json:"proxy_url"` - Height int `json:"height"` - Width int `json:"width"` - ContentType string `json:"content_type"` + Url string `json:"url"` + ProxyUrl *string `json:"proxy_url,omitempty"` + Height *int `json:"height,omitempty"` + Width *int `json:"width,omitempty"` + ContentType *string `json:"content_type,omitempty"` } func (i Thumbnail) Type() ComponentType { diff --git a/objects/interaction/component/component_user_select.go b/objects/interaction/component/component_user_select.go index c73a6a9..f9aa0d7 100644 --- a/objects/interaction/component/component_user_select.go +++ b/objects/interaction/component/component_user_select.go @@ -5,12 +5,14 @@ import ( ) type UserSelect struct { - CustomId string `json:"custom_id"` - Placeholder string `json:"placeholder,omitempty"` - MinValues *int `json:"min_values,omitempty"` - MaxValues *int `json:"max_values,omitempty"` - Disabled bool `json:"disabled"` - Required *bool `json:"required,omitempty"` + Id *int `json:"id,omitempty"` + CustomId string `json:"custom_id"` + Placeholder string `json:"placeholder,omitempty"` + DefaultValues []SelectDefaultValue `json:"default_values,omitempty"` + MinValues *int `json:"min_values,omitempty"` + MaxValues *int `json:"max_values,omitempty"` + Disabled bool `json:"disabled,omitempty"` + Required *bool `json:"required,omitempty"` } func (i UserSelect) Type() ComponentType { diff --git a/objects/interaction/component/componentbutton.go b/objects/interaction/component/componentbutton.go index c764644..f13bd0e 100644 --- a/objects/interaction/component/componentbutton.go +++ b/objects/interaction/component/componentbutton.go @@ -7,13 +7,14 @@ import ( ) type Button struct { - Label string `json:"label"` + Id *int `json:"id,omitempty"` + Label string `json:"label,omitempty"` CustomId string `json:"custom_id,omitempty"` Style ButtonStyle `json:"style"` Emoji *emoji.Emoji `json:"emoji,omitempty"` SkuId *uint64 `json:"sku_id,omitempty"` Url *string `json:"url,omitempty"` - Disabled bool `json:"disabled"` + Disabled bool `json:"disabled,omitempty"` } func (b Button) Type() ComponentType { diff --git a/objects/interaction/component/inputtext.go b/objects/interaction/component/inputtext.go index 6713e19..e099b3a 100644 --- a/objects/interaction/component/inputtext.go +++ b/objects/interaction/component/inputtext.go @@ -5,6 +5,7 @@ import ( ) type InputText struct { + Id *int `json:"id,omitempty"` Style TextStyleTypes `json:"style"` CustomId string `json:"custom_id"` Label *string `json:"label,omitempty"` diff --git a/objects/interaction/component/selectmenu.go b/objects/interaction/component/selectmenu.go index cc8366b..4dced2b 100644 --- a/objects/interaction/component/selectmenu.go +++ b/objects/interaction/component/selectmenu.go @@ -7,12 +7,13 @@ import ( ) type SelectMenu struct { + Id *int `json:"id,omitempty"` CustomId string `json:"custom_id"` Options []SelectOption `json:"options"` Placeholder string `json:"placeholder,omitempty"` MinValues *int `json:"min_values,omitempty"` MaxValues *int `json:"max_values,omitempty"` - Disabled bool `json:"disabled"` + Disabled bool `json:"disabled,omitempty"` Required *bool `json:"required,omitempty"` } @@ -21,7 +22,20 @@ type SelectOption struct { Value string `json:"value"` Description *string `json:"description,omitempty"` Emoji *emoji.Emoji `json:"emoji,omitempty"` - Default bool `json:"default"` + Default bool `json:"default,omitempty"` +} + +type SelectDefaultValueType string + +const ( + SelectDefaultValueTypeRole SelectDefaultValueType = "role" + SelectDefaultValueTypeUser SelectDefaultValueType = "user" + SelectDefaultValueTypeChannel SelectDefaultValueType = "channel" +) + +type SelectDefaultValue struct { + Id uint64 `json:"id,string"` + Type SelectDefaultValueType `json:"type"` } func (s SelectMenu) Type() ComponentType { From 5b36edf1d4e18f8be30e41263b61ca2e24ce902c Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 23:13:01 +0100 Subject: [PATCH 50/73] Rename ManageEmojis and add BypassSlowmode Rename the ManageEmojis permission to ManageGuildExpressions across the file (constant name, string representation, and AllPermissions list) to improve naming clarity. Also add a new BypassSlowmode permission and include it in the String() switch and AllPermissions slice. https://docs.discord.com/developers/topics/permissions --- permission/permission.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/permission/permission.go b/permission/permission.go index 9d7e2f2..9056968 100644 --- a/permission/permission.go +++ b/permission/permission.go @@ -33,7 +33,7 @@ const ( ManageNicknames ManageRoles // Manage permissions ManageWebhooks - ManageEmojis + ManageGuildExpressions UseApplicationCommands RequestToSpeak ManageEvents @@ -134,8 +134,8 @@ func (p Permission) String() string { return "Manage Roles" case ManageWebhooks: return "Manage Webhooks" - case ManageEmojis: - return "Manage Emojis" + case ManageGuildExpressions: + return "Manage Guild Expressions" case UseApplicationCommands: return "Use Application Commands" case RequestToSpeak: @@ -174,6 +174,8 @@ func (p Permission) String() string { return "Use External Apps" case PinMessages: return "Pin Messages" + case BypassSlowmode: + return "Bypass Slowmode" default: return "Unknown Permission" } @@ -210,7 +212,7 @@ var AllPermissions = []Permission{ ManageNicknames, ManageRoles, ManageWebhooks, - ManageEmojis, + ManageGuildExpressions, UseApplicationCommands, RequestToSpeak, ManageEvents, @@ -230,4 +232,5 @@ var AllPermissions = []Permission{ SendPolls, UseExternalApps, PinMessages, + BypassSlowmode, } From 1eb916e42577401fac19fac48b8468d0a94f251e Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 23:30:52 +0100 Subject: [PATCH 51/73] Enhance channel REST models and endpoints Update rest/channel.go to expand channel and message APIs: add new optional fields to ModifyChannelData (defaults, flags, thread defaults), extend EditMessageData with allowed mentions, attachments and components, and add GetAttachments helper. EditMessage now selects JSON vs multipart based on attachments. CreateInviteData now supports target_user_id and target_application_id. Change DeleteChannelPermissions to use nil content type and add FollowAnnouncementChannel to follow news channels. Thread APIs: add ListThreadMembersData with query builder and update ListThreadMembers signature, make thread-start payload fields optional and add rate limit fields, fix archived threads endpoint path, and normalize thread 'before' timestamp formatting to RFC3339 UTC. https://docs.discord.com/developers/resources/channel --- rest/channel.go | 134 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 100 insertions(+), 34 deletions(-) diff --git a/rest/channel.go b/rest/channel.go index ee8a177..931c5d2 100644 --- a/rest/channel.go +++ b/rest/channel.go @@ -36,15 +36,20 @@ func GetChannel(ctx context.Context, token string, rateLimiter *ratelimit.Rateli } type ModifyChannelData struct { - Name string `json:"name,omitempty"` - Position int `json:"position,omitempty"` - Topic string `json:"topic,omitempty"` - Nsfw bool `json:"nsfw,omitempty"` - RateLimitPerUser int `json:"rate_limit_per_user,omitempty"` - Bitrate int `json:"bitrate,omitempty"` - UserLimit int `json:"user_limit,omitempty"` - PermissionOverwrites []channel.PermissionOverwrite `json:"permission_overwrites,omitempty"` - ParentId uint64 `json:"parent_id,string,omitempty"` + Name string `json:"name,omitempty"` + Position int `json:"position,omitempty"` + Topic string `json:"topic,omitempty"` + Nsfw bool `json:"nsfw,omitempty"` + RateLimitPerUser int `json:"rate_limit_per_user,omitempty"` + Bitrate int `json:"bitrate,omitempty"` + UserLimit int `json:"user_limit,omitempty"` + PermissionOverwrites []channel.PermissionOverwrite `json:"permission_overwrites,omitempty"` + ParentId uint64 `json:"parent_id,string,omitempty"` + DefaultAutoArchiveDuration *uint16 `json:"default_auto_archive_duration,omitempty"` + Flags *int `json:"flags,omitempty"` + DefaultThreadRateLimitPerUser *int `json:"default_thread_rate_limit_per_user,omitempty"` + DefaultSortOrder *int `json:"default_sort_order,omitempty"` + DefaultForumLayout *int `json:"default_forum_layout,omitempty"` *ThreadMetadataModifyData } @@ -323,19 +328,36 @@ func DeleteAllReactionsEmoji(ctx context.Context, token string, rateLimiter *rat } type EditMessageData struct { - Content string `json:"content"` - Embeds []*embed.Embed `json:"embeds"` - Flags uint `json:"flags"` // https://discord.com/developers/docs/resources/channel#message-object-message-flags TODO: Helper function - Components []component.Component `json:"components"` + Content string `json:"content,omitempty"` + Embeds []*embed.Embed `json:"embeds,omitempty"` + Flags uint `json:"flags,omitempty"` + AllowedMentions *message.AllowedMention `json:"allowed_mentions,omitempty"` + Components []component.Component `json:"components,omitempty"` + Attachments []request.Attachment `json:"attachments,omitempty"` +} + +func (d EditMessageData) GetAttachments() []request.Attachment { + return d.Attachments } func EditMessage(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId, messageId uint64, data EditMessageData) (message.Message, error) { - endpoint := request.Endpoint{ - RequestType: request.PATCH, - ContentType: request.ApplicationJson, - Endpoint: fmt.Sprintf("/channels/%d/messages/%d", channelId, messageId), - Route: ratelimit.NewChannelRoute(ratelimit.RouteEditMessage, channelId), - RateLimiter: rateLimiter, + var endpoint request.Endpoint + if len(data.Attachments) == 0 { + endpoint = request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/channels/%d/messages/%d", channelId, messageId), + Route: ratelimit.NewChannelRoute(ratelimit.RouteEditMessage, channelId), + RateLimiter: rateLimiter, + } + } else { + endpoint = request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.MultipartFormData, + Endpoint: fmt.Sprintf("/channels/%d/messages/%d", channelId, messageId), + Route: ratelimit.NewChannelRoute(ratelimit.RouteEditMessage, channelId), + RateLimiter: rateLimiter, + } } var message message.Message @@ -409,12 +431,13 @@ func GetChannelInvites(ctx context.Context, token string, rateLimiter *ratelimit } type CreateInviteData struct { - MaxAge int `json:"max_age"` // seconds, 0 = never - MaxUses int `json:"max_uses"` // 0 = unlimited - Temporary bool `json:"temporary"` - Unique bool `json:"unique"` - TargetUser uint64 `json:"target_user,string,omitempty"` - TargetType int `json:"target_type,omitempty"` + MaxAge int `json:"max_age"` // seconds, 0 = never + MaxUses int `json:"max_uses"` // 0 = unlimited + Temporary bool `json:"temporary"` + Unique bool `json:"unique"` + TargetType int `json:"target_type,omitempty"` + TargetUserId *uint64 `json:"target_user_id,string,omitempty"` + TargetApplicationId *uint64 `json:"target_application_id,string,omitempty"` } func CreateChannelInvite(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64, data CreateInviteData) (invite.Invite, error) { @@ -437,7 +460,7 @@ func CreateChannelInvite(ctx context.Context, token string, rateLimiter *ratelim func DeleteChannelPermissions(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId, overwriteId uint64) error { endpoint := request.Endpoint{ RequestType: request.DELETE, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/channels/%d/permissions/%d", channelId, overwriteId), Route: ratelimit.NewChannelRoute(ratelimit.RouteDeleteChannelPermission, channelId), RateLimiter: rateLimiter, @@ -447,6 +470,23 @@ func DeleteChannelPermissions(ctx context.Context, token string, rateLimiter *ra return err } +func FollowAnnouncementChannel(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId, webhookChannelId uint64) error { + endpoint := request.Endpoint{ + RequestType: request.POST, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/channels/%d/followers", channelId), + Route: ratelimit.NewChannelRoute(ratelimit.RouteFollowNewsChannel, channelId), + RateLimiter: rateLimiter, + } + + body := map[string]interface{}{ + "webhook_channel_id": strconv.FormatUint(webhookChannelId, 10), + } + + err, _ := endpoint.Request(ctx, token, body, nil) + return err +} + func TriggerTypingIndicator(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64) error { endpoint := request.Endpoint{ RequestType: request.POST, @@ -568,11 +608,35 @@ func GetThreadMember(ctx context.Context, token string, rateLimiter *ratelimit.R return } -func ListThreadMembers(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64) (members []channel.ThreadMember, err error) { +type ListThreadMembersData struct { + WithMember bool // include guild member data for each thread member + After uint64 // get thread members after this user ID + Limit int // max 100 +} + +func (d *ListThreadMembersData) Query() string { + query := url.Values{} + + if d.WithMember { + query.Set("with_member", "true") + } + + if d.After != 0 { + query.Set("after", strconv.FormatUint(d.After, 10)) + } + + if d.Limit > 0 { + query.Set("limit", strconv.Itoa(d.Limit)) + } + + return query.Encode() +} + +func ListThreadMembers(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64, data ListThreadMembersData) (members []channel.ThreadMember, err error) { endpoint := request.Endpoint{ RequestType: request.GET, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/channels/%d/thread-members", channelId), + Endpoint: fmt.Sprintf("/channels/%d/thread-members?%s", channelId, data.Query()), Route: ratelimit.NewChannelRoute(ratelimit.RouteListThreadMembers, channelId), RateLimiter: rateLimiter, } @@ -583,7 +647,8 @@ func ListThreadMembers(ctx context.Context, token string, rateLimiter *ratelimit type StartThreadWithMessageData struct { Name string `json:"name"` - AutoArchiveDuration uint16 `json:"auto_archive_duration"` + AutoArchiveDuration uint16 `json:"auto_archive_duration,omitempty"` + RateLimitPerUser *int `json:"rate_limit_per_user,omitempty"` } func StartThreadWithMessage(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId, messageId uint64, data StartThreadWithMessageData) (ch channel.Channel, err error) { @@ -601,9 +666,10 @@ func StartThreadWithMessage(ctx context.Context, token string, rateLimiter *rate type StartThreadWithoutMessageData struct { Name string `json:"name"` - AutoArchiveDuration uint16 `json:"auto_archive_duration"` - Type channel.ChannelType `json:"type"` - Invitable bool `json:"invitable"` + AutoArchiveDuration uint16 `json:"auto_archive_duration,omitempty"` + Type channel.ChannelType `json:"type,omitempty"` + Invitable bool `json:"invitable,omitempty"` + RateLimitPerUser *int `json:"rate_limit_per_user,omitempty"` } func StartThreadWithoutMessage(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64, data StartThreadWithoutMessageData) (ch channel.Channel, err error) { @@ -647,7 +713,7 @@ func (d *ListThreadsData) Query() string { query := url.Values{} if !d.Before.IsZero() { - query.Set("before", d.Before.String()) + query.Set("before", d.Before.UTC().Format(time.RFC3339)) } if d.Limit > 0 { @@ -687,7 +753,7 @@ func ListJoinedPrivateArchivedThreads(ctx context.Context, token string, rateLim endpoint := request.Endpoint{ RequestType: request.GET, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/channels/%d/usrs/@methreads/archived/private?%s", channelId, data.Query()), + Endpoint: fmt.Sprintf("/channels/%d/users/@me/threads/archived/private?%s", channelId, data.Query()), Route: ratelimit.NewChannelRoute(ratelimit.RouteGetArchivedPrivateThreads, channelId), RateLimiter: rateLimiter, } From 8a397ca5edf25a8006291f39192d4eb5b9460575 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 3 Mar 2026 23:48:34 +0100 Subject: [PATCH 52/73] Update guild REST API structs and endpoints Refactor guild REST layer: make many request payload fields pointers with `omitempty` and add new fields (discovery_splash, system_channel_flags, features, description, premium_progress_bar_enabled, safety_alerts_channel_id, etc.). Extend channel/position structs with new channel options and permissions/parent support. Convert member modification fields to pointers and add communication_disabled_until and flags. Change many no-body endpoints to use request.Nil ContentType. Replace prune query API with BeginGuildPruneData body. Adjust ban payload field to delete_message_seconds. Update role payload to support icon and unicode_emoji. Rename and split widget/embed endpoints: introduce GetGuildWidgetSettings/ModifyGuildWidget, keep deprecated ModifyGuildEmbed wrapper, and reintroduce GetGuildWidget for the legacy widget.json. Add time import for communication timeout handling. https://docs.discord.com/developers/resources/guild --- rest/guild.go | 155 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 100 insertions(+), 55 deletions(-) diff --git a/rest/guild.go b/rest/guild.go index 98f73d4..8d447ea 100644 --- a/rest/guild.go +++ b/rest/guild.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "strconv" + "time" "github.com/TicketsBot-cloud/gdl/objects/channel" "github.com/TicketsBot-cloud/gdl/objects/guild" @@ -74,22 +75,28 @@ func GetGuildPreview(ctx context.Context, token string, rateLimiter *ratelimit.R } type ModifyGuildData struct { - Name string `json:"name"` - Region string `json:"region"` // voice region ID TODO: Helper function - VerificationLevel guild.VerificationLevel `json:"verification_level"` - DefaultMessageNotifications guild.DefaultMessageNotificationLevel `json:"default_message_notifications"` - ExplicitContentFilter guild.ExplicitContentFilterLevel `json:"explicit_content_filter"` - AfkChannelId uint64 `json:"afk_channel_id,string"` - AfkTimeout int `json:"afk_timeout"` - Icon string `json:"icon"` - OwnerId uint64 `json:"owner_id"` - Splash string `json:"splash"` - Banner string `json:"banner"` - SystemChannelId uint64 `json:"system_channel_id"` - RulesChannelId uint64 `json:"rules_channel_id"` - PublicUpdatesChannelId uint64 `json:"public_updates_channel_id"` - PreferredLocale string `json:"preferred_locale"` -} + Name string `json:"name,omitempty"` + Region *string `json:"region,omitempty"` // voice region ID, deprecated + VerificationLevel *guild.VerificationLevel `json:"verification_level,omitempty"` + DefaultMessageNotifications *guild.DefaultMessageNotificationLevel `json:"default_message_notifications,omitempty"` + ExplicitContentFilter *guild.ExplicitContentFilterLevel `json:"explicit_content_filter,omitempty"` + AfkChannelId *uint64 `json:"afk_channel_id,string,omitempty"` + AfkTimeout *int `json:"afk_timeout,omitempty"` + Icon *string `json:"icon,omitempty"` + OwnerId *uint64 `json:"owner_id,string,omitempty"` + Splash *string `json:"splash,omitempty"` + DiscoverySplash *string `json:"discovery_splash,omitempty"` + Banner *string `json:"banner,omitempty"` + SystemChannelId *uint64 `json:"system_channel_id,string,omitempty"` + SystemChannelFlags *int `json:"system_channel_flags,omitempty"` + RulesChannelId *uint64 `json:"rules_channel_id,string,omitempty"` + PublicUpdatesChannelId *uint64 `json:"public_updates_channel_id,string,omitempty"` + PreferredLocale *string `json:"preferred_locale,omitempty"` + Features []string `json:"features,omitempty"` + Description *string `json:"description,omitempty"` + PremiumProgressBarEnabled *bool `json:"premium_progress_bar_enabled,omitempty"` + SafetyAlertsChannelId *uint64 `json:"safety_alerts_channel_id,string,omitempty"` +} func ModifyGuild(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data ModifyGuildData) (guild.Guild, error) { endpoint := request.Endpoint{ @@ -108,7 +115,7 @@ func ModifyGuild(ctx context.Context, token string, rateLimiter *ratelimit.Ratel func DeleteGuild(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) error { endpoint := request.Endpoint{ RequestType: request.DELETE, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/guilds/%d", guildId), Route: ratelimit.NewGuildRoute(ratelimit.RouteDeleteGuild, guildId), RateLimiter: rateLimiter, @@ -133,16 +140,24 @@ func GetGuildChannels(ctx context.Context, token string, rateLimiter *ratelimit. } type CreateChannelData struct { - Name string `json:"name"` - Type channel.ChannelType `json:"type"` - Topic string `json:"topic,omitempty"` - Bitrate int `json:"bitrate,omitempty"` - UserLimit int `json:"user_limit,omitempty"` - RateLimitPerUser int `json:"rate_limit_per_user"` - Position int `json:"position,omitempty"` - PermissionOverwrites []channel.PermissionOverwrite `json:"permission_overwrites"` - ParentId uint64 `json:"parent_id,string,omitempty"` - Nsfw bool `json:"nsfw,omitempty"` + Name string `json:"name"` + Type channel.ChannelType `json:"type,omitempty"` + Topic *string `json:"topic,omitempty"` + Bitrate *int `json:"bitrate,omitempty"` + UserLimit *int `json:"user_limit,omitempty"` + RateLimitPerUser *int `json:"rate_limit_per_user,omitempty"` + Position *int `json:"position,omitempty"` + PermissionOverwrites []channel.PermissionOverwrite `json:"permission_overwrites,omitempty"` + ParentId *uint64 `json:"parent_id,string,omitempty"` + Nsfw *bool `json:"nsfw,omitempty"` + RtcRegion *string `json:"rtc_region,omitempty"` + VideoQualityMode *int `json:"video_quality_mode,omitempty"` + DefaultAutoArchiveDuration *int `json:"default_auto_archive_duration,omitempty"` + DefaultReactionEmoji *channel.DefaultReaction `json:"default_reaction_emoji,omitempty"` + AvailableTags []channel.ForumTag `json:"available_tags,omitempty"` + DefaultSortOrder *int `json:"default_sort_order,omitempty"` + DefaultForumLayout *int `json:"default_forum_layout,omitempty"` + DefaultThreadRateLimitPerUser *int `json:"default_thread_rate_limit_per_user,omitempty"` } func CreateGuildChannel(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data CreateChannelData) (channel.Channel, error) { @@ -160,8 +175,10 @@ func CreateGuildChannel(ctx context.Context, token string, rateLimiter *ratelimi } type Position struct { - ChannelId uint64 `json:"id,string"` - Position int `json:"position"` + ChannelId uint64 `json:"id,string"` + Position int `json:"position"` + LockPermissions *bool `json:"lock_permissions,omitempty"` + ParentId *uint64 `json:"parent_id,string,omitempty"` } func ModifyGuildChannelPositions(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, positions []Position) error { @@ -256,11 +273,13 @@ func ListGuildMembers(ctx context.Context, token string, rateLimiter *ratelimit. } type ModifyGuildMemberData struct { - Nick string `json:"nick,omitempty"` - Roles *utils.Uint64StringSlice `json:"roles,omitempty"` - Mute *bool `json:"mute,omitempty"` - Deaf *bool `json:"deaf,omitempty"` - ChannelId uint64 `json:"channel_id,string,omitempty"` // id of channel to move user to (if they are connected to voice) + Nick *string `json:"nick,omitempty"` + Roles *utils.Uint64StringSlice `json:"roles,omitempty"` + Mute *bool `json:"mute,omitempty"` + Deaf *bool `json:"deaf,omitempty"` + ChannelId *uint64 `json:"channel_id,string,omitempty"` // id of channel to move user to (if they are connected to voice) + CommunicationDisabledUntil *time.Time `json:"communication_disabled_until,omitempty"` + Flags *int `json:"flags,omitempty"` } func ModifyGuildMember(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, userId uint64, data ModifyGuildMemberData) error { @@ -296,7 +315,7 @@ func ModifyCurrentUserNick(ctx context.Context, token string, rateLimiter *ratel func AddGuildMemberRole(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, userId, roleId uint64) error { endpoint := request.Endpoint{ RequestType: request.PUT, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/guilds/%d/members/%d/roles/%d", guildId, userId, roleId), Route: ratelimit.NewGuildRoute(ratelimit.RouteAddGuildMemberRole, guildId), RateLimiter: rateLimiter, @@ -309,7 +328,7 @@ func AddGuildMemberRole(ctx context.Context, token string, rateLimiter *ratelimi func RemoveGuildMemberRole(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, userId, roleId uint64) error { endpoint := request.Endpoint{ RequestType: request.DELETE, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/guilds/%d/members/%d/roles/%d", guildId, userId, roleId), Route: ratelimit.NewGuildRoute(ratelimit.RouteRemoveGuildMemberRole, guildId), RateLimiter: rateLimiter, @@ -322,7 +341,7 @@ func RemoveGuildMemberRole(ctx context.Context, token string, rateLimiter *ratel func RemoveGuildMember(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, userId uint64) error { endpoint := request.Endpoint{ RequestType: request.DELETE, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/guilds/%d/members/%d", guildId, userId), Route: ratelimit.NewGuildRoute(ratelimit.RouteRemoveGuildMember, guildId), RateLimiter: rateLimiter, @@ -385,7 +404,7 @@ func GetGuildBan(ctx context.Context, token string, rateLimiter *ratelimit.Ratel } type CreateGuildBanData struct { - DeleteMessageDays int `json:"delete_message_days,omitempty"` // 1 - 7 + DeleteMessageSeconds int `json:"delete_message_seconds,omitempty"` // 0 - 604800 (7 days) } func CreateGuildBan(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, userId uint64, data CreateGuildBanData) error { @@ -429,11 +448,13 @@ func GetGuildRoles(ctx context.Context, token string, rateLimiter *ratelimit.Rat } type GuildRoleData struct { - Name string `json:"name,omitempty"` - Permissions *uint64 `json:"permissions,omitempty,string"` - Color *int `json:"color,omitempty"` - Hoist *bool `json:"hoist,omitempty"` - Mentionable *bool `json:"mentionable,omitempty"` + Name string `json:"name,omitempty"` + Permissions *uint64 `json:"permissions,string,omitempty"` + Color *int `json:"color,omitempty"` + Hoist *bool `json:"hoist,omitempty"` + Icon *string `json:"icon,omitempty"` + UnicodeEmoji *string `json:"unicode_emoji,omitempty"` + Mentionable *bool `json:"mentionable,omitempty"` } func CreateGuildRole(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data GuildRoleData) (guild.Role, error) { @@ -481,7 +502,7 @@ func ModifyGuildRole(ctx context.Context, token string, rateLimiter *ratelimit.R func DeleteGuildRole(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, roleId uint64) error { endpoint := request.Endpoint{ RequestType: request.DELETE, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/guilds/%d/roles/%d", guildId, roleId), Route: ratelimit.NewGuildRoute(ratelimit.RouteDeleteGuildRole, guildId), RateLimiter: rateLimiter, @@ -509,17 +530,23 @@ func GetGuildPruneCount(ctx context.Context, token string, rateLimiter *ratelimi return res["pruned"], err } +type BeginGuildPruneData struct { + Days int `json:"days,omitempty"` + ComputePruneCount bool `json:"compute_prune_count"` + IncludeRoles []uint64 `json:"include_roles,omitempty"` +} + // computePruneCount = whether 'pruned' is returned, discouraged for large guilds -func BeginGuildPrune(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, days int, computePruneCount bool) error { +func BeginGuildPrune(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data BeginGuildPruneData) error { endpoint := request.Endpoint{ RequestType: request.POST, ContentType: request.ApplicationJson, - Endpoint: fmt.Sprintf("/guilds/%d/prune?days=%d&compute_prune_count=%t", guildId, days, computePruneCount), + Endpoint: fmt.Sprintf("/guilds/%d/prune", guildId), Route: ratelimit.NewGuildRoute(ratelimit.RouteBeginGuildPrune, guildId), RateLimiter: rateLimiter, } - err, _ := endpoint.Request(ctx, token, nil, nil) + err, _ := endpoint.Request(ctx, token, data, nil) return err } @@ -605,7 +632,7 @@ func ModifyGuildIntegration(ctx context.Context, token string, rateLimiter *rate func DeleteGuildIntegration(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, integrationId uint64) error { endpoint := request.Endpoint{ RequestType: request.DELETE, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/guilds/%d/integrations/%d", guildId, integrationId), Route: ratelimit.NewGuildRoute(ratelimit.RouteDeleteGuildIntegration, guildId), RateLimiter: rateLimiter, @@ -618,7 +645,7 @@ func DeleteGuildIntegration(ctx context.Context, token string, rateLimiter *rate func SyncGuildIntegration(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, integrationId uint64) error { endpoint := request.Endpoint{ RequestType: request.POST, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/guilds/%d/integrations/%d/sync", guildId, integrationId), Route: ratelimit.NewGuildRoute(ratelimit.RouteSyncGuildIntegration, guildId), RateLimiter: rateLimiter, @@ -628,24 +655,24 @@ func SyncGuildIntegration(ctx context.Context, token string, rateLimiter *rateli return err } -func GetGuildWidget(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) (widget guild.GuildWidget, err error) { +func GetGuildWidgetSettings(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) (settings guild.GuildEmbed, err error) { endpoint := request.Endpoint{ RequestType: request.GET, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/guilds/%d/widget.json", guildId), - Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildWidget, guildId), + Endpoint: fmt.Sprintf("/guilds/%d/widget", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildWidgetSettings, guildId), RateLimiter: rateLimiter, } - err, _ = endpoint.Request(ctx, token, nil, &widget) + err, _ = endpoint.Request(ctx, token, nil, &settings) return } -func ModifyGuildEmbed(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data guild.GuildEmbed) (widget guild.GuildEmbed, err error) { +func ModifyGuildWidget(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data guild.GuildEmbed) (widget guild.GuildEmbed, err error) { endpoint := request.Endpoint{ RequestType: request.PATCH, ContentType: request.ApplicationJson, - Endpoint: fmt.Sprintf("/guilds/%d/embed", guildId), + Endpoint: fmt.Sprintf("/guilds/%d/widget", guildId), Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyGuildWidget, guildId), RateLimiter: rateLimiter, } @@ -654,6 +681,24 @@ func ModifyGuildEmbed(ctx context.Context, token string, rateLimiter *ratelimit. return } +// Deprecated: Use ModifyGuildWidget instead. +func ModifyGuildEmbed(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data guild.GuildEmbed) (widget guild.GuildEmbed, err error) { + return ModifyGuildWidget(ctx, token, rateLimiter, guildId, data) +} + +func GetGuildWidget(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) (widget guild.GuildWidget, err error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/widget.json", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildWidget, guildId), + RateLimiter: rateLimiter, + } + + err, _ = endpoint.Request(ctx, token, nil, &widget) + return +} + // returns invite object with only "code" and "uses" fields func GetGuildVanityURL(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) (invite invite.Invite, err error) { endpoint := request.Endpoint{ From 205eafeeee7686b8b745e464180c66f933b91040 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 00:02:19 +0100 Subject: [PATCH 53/73] Add get command endpoints & update command data Add endpoints to retrieve a single global or guild application command (GetGlobalCommand, GetGuildCommand) and add with_localizations query option to list endpoints. Expand CreateCommandData with localization fields, permissions, integration types, nsfw, handler and other optional fields to match Discord API command payloads. Register new ratelimit route constants for per-command GETs and fix webhook route used for deleting the original interaction response. Also import the application package where required. --- rest/interaction.go | 55 ++++++++++++++++++++++++++++++++-------- rest/ratelimit/routes.go | 2 ++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/rest/interaction.go b/rest/interaction.go index f12625f..e2d5734 100644 --- a/rest/interaction.go +++ b/rest/interaction.go @@ -4,17 +4,18 @@ import ( "context" "fmt" + "github.com/TicketsBot-cloud/gdl/objects/application" "github.com/TicketsBot-cloud/gdl/objects/channel/message" "github.com/TicketsBot-cloud/gdl/objects/interaction" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" "github.com/TicketsBot-cloud/gdl/rest/request" ) -func GetGlobalCommands(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId uint64) (commands []interaction.ApplicationCommand, err error) { +func GetGlobalCommands(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId uint64, withLocalizations bool) (commands []interaction.ApplicationCommand, err error) { endpoint := request.Endpoint{ RequestType: request.GET, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/applications/%d/commands", applicationId), + Endpoint: fmt.Sprintf("/applications/%d/commands?with_localizations=%t", applicationId, withLocalizations), Route: ratelimit.NewApplicationRoute(ratelimit.RouteGetGlobalCommands, applicationId), RateLimiter: rateLimiter, } @@ -23,13 +24,32 @@ func GetGlobalCommands(ctx context.Context, token string, rateLimiter *ratelimit return } +func GetGlobalCommand(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, commandId uint64) (command interaction.ApplicationCommand, err error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/applications/%d/commands/%d", applicationId, commandId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteGetGlobalCommand, applicationId), + RateLimiter: rateLimiter, + } + + err, _ = endpoint.Request(ctx, token, nil, &command) + return +} + type CreateCommandData struct { - Id uint64 `json:"id,omitempty"` // Optional: Use to rename without changing ID - Name string `json:"name"` - Description string `json:"description"` - Options []interaction.ApplicationCommandOption `json:"options"` - Type interaction.ApplicationCommandType `json:"type"` - Contexts []interaction.InteractionContextType `json:"contexts,omitempty"` + Id uint64 `json:"id,string,omitempty"` // Use in bulk overwrite to update an existing command by ID + Name string `json:"name"` + NameLocalizations map[string]string `json:"name_localizations,omitempty"` + Description string `json:"description,omitempty"` + DescriptionLocalizations map[string]string `json:"description_localizations,omitempty"` + Options []interaction.ApplicationCommandOption `json:"options,omitempty"` + DefaultMemberPermissions *string `json:"default_member_permissions,omitempty"` + IntegrationTypes []application.ApplicationIntegrationType `json:"integration_types,omitempty"` + Contexts []interaction.InteractionContextType `json:"contexts,omitempty"` + Type interaction.ApplicationCommandType `json:"type,omitempty"` + Nsfw *bool `json:"nsfw,omitempty"` + Handler *interaction.ApplicationCommandHandlerType `json:"handler,omitempty"` } func CreateGlobalCommand(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId uint64, data CreateCommandData) (command interaction.ApplicationCommand, err error) { @@ -84,11 +104,11 @@ func DeleteGlobalCommand(ctx context.Context, token string, rateLimiter *ratelim return } -func GetGuildCommands(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, guildId uint64) (commands []interaction.ApplicationCommand, err error) { +func GetGuildCommands(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, guildId uint64, withLocalizations bool) (commands []interaction.ApplicationCommand, err error) { endpoint := request.Endpoint{ RequestType: request.GET, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/applications/%d/guilds/%d/commands", applicationId, guildId), + Endpoint: fmt.Sprintf("/applications/%d/guilds/%d/commands?with_localizations=%t", applicationId, guildId, withLocalizations), Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildCommands, applicationId), RateLimiter: rateLimiter, } @@ -97,6 +117,19 @@ func GetGuildCommands(ctx context.Context, token string, rateLimiter *ratelimit. return } +func GetGuildCommand(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, guildId, commandId uint64) (command interaction.ApplicationCommand, err error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/applications/%d/guilds/%d/commands/%d", applicationId, guildId, commandId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildCommand, applicationId), + RateLimiter: rateLimiter, + } + + err, _ = endpoint.Request(ctx, token, nil, &command) + return +} + func CreateGuildCommand(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, guildId uint64, data CreateCommandData) (command interaction.ApplicationCommand, err error) { endpoint := request.Endpoint{ RequestType: request.POST, @@ -239,7 +272,7 @@ func DeleteOriginalInteractionResponse(ctx context.Context, token string, rateLi RequestType: request.DELETE, ContentType: request.Nil, Endpoint: fmt.Sprintf("/webhooks/%d/%s/messages/@original", applicationId, token), - Route: ratelimit.NewWebhookRoute(ratelimit.RouteEditOriginalInteractionResponse, applicationId), + Route: ratelimit.NewWebhookRoute(ratelimit.RouteDeleteOriginalInteractionResponse, applicationId), RateLimiter: rateLimiter, } diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index fec1b68..d27b073 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -184,6 +184,7 @@ const ( // /applications/:id/... RouteGetGlobalCommands + RouteGetGlobalCommand RouteCreateGlobalCommand RouteModifyGlobalCommand RouteModifyGlobalCommands @@ -191,6 +192,7 @@ const ( // /applications/:id/guild/... RouteGetGuildCommands + RouteGetGuildCommand RouteCreateGuildCommand RouteModifyGuildCommand RouteModifyGuildCommands From 94671db1e6cb396fed836d3b58ff511d2a69efb7 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 00:07:07 +0100 Subject: [PATCH 54/73] Webhook message: add GET/DELETE, edit -> PATCH Add support for fetching and deleting webhook messages (GetWebhookMessage, DeleteWebhookMessage) and corresponding rate-limit routes. Change EditWebhookMessage to use PATCH (previously POST) for both JSON and multipart branches. Also update WebhookBody: make Tts omitempty and add ThreadId to support thread targeting. These changes align the client with Discord webhook message API semantics and thread support. https://docs.discord.com/developers/resources/webhook --- rest/ratelimit/routes.go | 2 ++ rest/webhook.go | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index d27b073..7666fee 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -180,7 +180,9 @@ const ( RouteDeleteWebhook RouteDeleteWebhookWithToken RouteExecuteWebhook + RouteGetWebhookMessage RouteEditWebhookMessage + RouteDeleteWebhookMessage // /applications/:id/... RouteGetGlobalCommands diff --git a/rest/webhook.go b/rest/webhook.go index 2e88d2f..09e27dc 100644 --- a/rest/webhook.go +++ b/rest/webhook.go @@ -151,12 +151,13 @@ type WebhookBody struct { Content string `json:"content,omitempty"` Username string `json:"username,omitempty"` AvatarUrl string `json:"avatar_url,omitempty"` - Tts bool `json:"tts"` + Tts bool `json:"tts,omitempty"` Flags uint `json:"flags,omitempty"` Embeds []*embed.Embed `json:"embeds,omitempty"` AllowedMentions message.AllowedMention `json:"allowed_mentions,omitempty"` Components []component.Component `json:"components,omitempty"` Attachments []request.Attachment `json:"attachments,omitempty"` + ThreadId *uint64 `json:"thread_id,string,omitempty"` ThreadName string `json:"thread_name,omitempty"` } @@ -210,12 +211,25 @@ func (d WebhookEditBody) GetAttachments() []request.Attachment { return d.Attachments } +func GetWebhookMessage(ctx context.Context, webhookToken string, rateLimiter *ratelimit.Ratelimiter, webhookId, messageId uint64) (msg message.Message, err error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/webhooks/%d/%s/messages/%d", webhookId, webhookToken, messageId), + Route: ratelimit.NewWebhookRoute(ratelimit.RouteGetWebhookMessage, webhookId), + RateLimiter: rateLimiter, + } + + err, _ = endpoint.Request(ctx, "", nil, &msg) + return +} + func EditWebhookMessage(ctx context.Context, webhookToken string, rateLimiter *ratelimit.Ratelimiter, webhookId, messageId uint64, data WebhookEditBody) (msg message.Message, err error) { var endpoint request.Endpoint if len(data.Attachments) == 0 { endpoint = request.Endpoint{ - RequestType: request.POST, + RequestType: request.PATCH, ContentType: request.ApplicationJson, Endpoint: fmt.Sprintf("/webhooks/%d/%s/messages/%d", webhookId, webhookToken, messageId), Route: ratelimit.NewWebhookRoute(ratelimit.RouteEditWebhookMessage, webhookId), @@ -223,7 +237,7 @@ func EditWebhookMessage(ctx context.Context, webhookToken string, rateLimiter *r } } else { endpoint = request.Endpoint{ - RequestType: request.POST, + RequestType: request.PATCH, ContentType: request.MultipartFormData, Endpoint: fmt.Sprintf("/webhooks/%d/%s/messages/%d", webhookId, webhookToken, messageId), Route: ratelimit.NewWebhookRoute(ratelimit.RouteEditWebhookMessage, webhookId), @@ -234,3 +248,16 @@ func EditWebhookMessage(ctx context.Context, webhookToken string, rateLimiter *r err, _ = endpoint.Request(ctx, "", data, &msg) return } + +func DeleteWebhookMessage(ctx context.Context, webhookToken string, rateLimiter *ratelimit.Ratelimiter, webhookId, messageId uint64) (err error) { + endpoint := request.Endpoint{ + RequestType: request.DELETE, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/webhooks/%d/%s/messages/%d", webhookId, webhookToken, messageId), + Route: ratelimit.NewWebhookRoute(ratelimit.RouteDeleteWebhookMessage, webhookId), + RateLimiter: rateLimiter, + } + + err, _ = endpoint.Request(ctx, "", nil, nil) + return +} From 2c00b15f663434f3c996b595cfe77cb2ec6ed4c9 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:09:27 +0100 Subject: [PATCH 55/73] user: add banner, guild member endpoint, and query fixes Add RouteGetCurrentUserGuildMember and implement GetCurrentUserGuildMember to fetch the current user's guild member object. Make ModifyUserData fields more explicit: Avatar and Banner are optional pointers; Username formatting adjusted. Improve CurrentUserGuildsData handling: only set limit when 1-200 and add with_counts flag to include member counts. Also simplify some endpoint strings (remove unnecessary fmt.Sprintf) and import the member package. These changes enable fetching guild member info, optional avatar/banner updates, and more correct guild list query params. https://docs.discord.com/developers/resources/user --- rest/ratelimit/routes.go | 1 + rest/user.go | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index 7666fee..4ec1bb4 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -156,6 +156,7 @@ const ( RouteGetUser RouteModifyCurrentUser RouteGetCurrentUserGuilds + RouteGetCurrentUserGuildMember RouteLeaveGuild RouteGetUserDMs RouteCreateDM diff --git a/rest/user.go b/rest/user.go index ac5be0f..e742a5b 100644 --- a/rest/user.go +++ b/rest/user.go @@ -9,6 +9,7 @@ import ( "github.com/TicketsBot-cloud/gdl/objects/channel" "github.com/TicketsBot-cloud/gdl/objects/guild" "github.com/TicketsBot-cloud/gdl/objects/integration" + "github.com/TicketsBot-cloud/gdl/objects/member" "github.com/TicketsBot-cloud/gdl/objects/user" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" "github.com/TicketsBot-cloud/gdl/rest/request" @@ -43,8 +44,9 @@ func GetUser(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimit } type ModifyUserData struct { - Username string `json:"username,omitempty"` - Avatar string `json:"avatar,omitempty"` + Username string `json:"username,omitempty"` + Avatar *string `json:"avatar,omitempty"` + Banner *string `json:"banner,omitempty"` } func ModifyCurrentUser(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, data ModifyUserData) (user.User, error) { @@ -62,9 +64,10 @@ func ModifyCurrentUser(ctx context.Context, token string, rateLimiter *ratelimit } type CurrentUserGuildsData struct { - Before uint64 - After uint64 - Limit int + Before uint64 + After uint64 + Limit int // 1-200, omitted if 0 + WithCounts bool } func (d *CurrentUserGuildsData) Query() string { @@ -78,10 +81,13 @@ func (d *CurrentUserGuildsData) Query() string { query.Set("after", strconv.FormatUint(d.After, 10)) } - if d.Limit > 200 || d.Limit < 1 { - d.Limit = 200 + if d.Limit >= 1 && d.Limit <= 200 { + query.Set("limit", strconv.Itoa(d.Limit)) + } + + if d.WithCounts { + query.Set("with_counts", "true") } - query.Set("limit", strconv.Itoa(d.Limit)) return query.Encode() } @@ -100,6 +106,20 @@ func GetCurrentUserGuilds(ctx context.Context, token string, rateLimiter *rateli return guilds, err } +func GetCurrentUserGuildMember(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) (member.Member, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/users/@me/guilds/%d/member", guildId), + Route: ratelimit.NewOtherRoute(ratelimit.RouteGetCurrentUserGuildMember, 0), + RateLimiter: rateLimiter, + } + + var m member.Member + err, _ := endpoint.Request(ctx, token, nil, &m) + return m, err +} + func LeaveGuild(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) error { endpoint := request.Endpoint{ RequestType: request.DELETE, @@ -117,7 +137,7 @@ func CreateDM(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimi endpoint := request.Endpoint{ RequestType: request.POST, ContentType: request.ApplicationJson, - Endpoint: fmt.Sprintf("/users/@me/channels"), + Endpoint: "/users/@me/channels", Route: ratelimit.NewOtherRoute(ratelimit.RouteCreateDM, recipientId), RateLimiter: rateLimiter, } @@ -135,7 +155,7 @@ func GetUserConnections(ctx context.Context, token string, rateLimiter *ratelimi endpoint := request.Endpoint{ RequestType: request.GET, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/users/@me/connections"), + Endpoint: "/users/@me/connections", Route: ratelimit.NewOtherRoute(ratelimit.RouteGetUserConnections, 0), RateLimiter: rateLimiter, } From d44f9ff296100ef7f8c55e78e0d5baa501809e04 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:11:27 +0100 Subject: [PATCH 56/73] Add activity instance types and endpoint Introduce ActivityLocation and ActivityInstance types (objects/application/activityinstance.go) and add a GetActivityInstance REST function to fetch /applications/:id/activity-instances/:instance_id. Expand EditCurrentApplicationData with additional fields (integration types config, icon, cover image, event webhooks, etc.) and register RouteGetActivityInstance in ratelimit routes. Also add fmt import used for endpoint formatting. https://docs.discord.com/developers/resources/application --- objects/application/activityinstance.go | 16 +++++++++++ rest/application.go | 37 +++++++++++++++++++------ rest/ratelimit/routes.go | 1 + 3 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 objects/application/activityinstance.go diff --git a/objects/application/activityinstance.go b/objects/application/activityinstance.go new file mode 100644 index 0000000..d70851a --- /dev/null +++ b/objects/application/activityinstance.go @@ -0,0 +1,16 @@ +package application + +type ActivityLocation struct { + Id string `json:"id"` + Kind string `json:"kind"` + ChannelId uint64 `json:"channel_id,string"` + GuildId *uint64 `json:"guild_id,string,omitempty"` +} + +type ActivityInstance struct { + ApplicationId uint64 `json:"application_id,string"` + InstanceId string `json:"instance_id"` + LaunchId string `json:"launch_id"` + Location ActivityLocation `json:"location"` + Users []uint64 `json:"users"` +} diff --git a/rest/application.go b/rest/application.go index d6094b7..cf63451 100644 --- a/rest/application.go +++ b/rest/application.go @@ -2,6 +2,7 @@ package rest import ( "context" + "fmt" "github.com/TicketsBot-cloud/gdl/objects/application" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" @@ -23,15 +24,19 @@ func GetCurrentApplication(ctx context.Context, token string, rateLimiter *ratel } type EditCurrentApplicationData struct { - CustomInstallUrl *string `json:"custom_install_url,omitempty"` - Description *string `json:"description,omitempty"` - RoleConnectionsVerificationUrl *string `json:"role_connections_verification_url,omitempty"` - InstallParams *application.InstallParams `json:"install_params,omitempty"` - Flags *application.Flag `json:"flags,omitempty"` - // TODO: icon - // TODO: cover_image - InteractionsEndpointUrl *string `json:"interactions_endpoint_url,omitempty"` - Tags []string `json:"tags,omitempty"` + CustomInstallUrl *string `json:"custom_install_url,omitempty"` + Description *string `json:"description,omitempty"` + RoleConnectionsVerificationUrl *string `json:"role_connections_verification_url,omitempty"` + InstallParams *application.InstallParams `json:"install_params,omitempty"` + IntegrationTypesConfig map[application.ApplicationIntegrationType]application.ApplicationIntegrationTypeConfig `json:"integration_types_config,omitempty"` + Flags *application.Flag `json:"flags,omitempty"` + Icon *string `json:"icon,omitempty"` + CoverImage *string `json:"cover_image,omitempty"` + InteractionsEndpointUrl *string `json:"interactions_endpoint_url,omitempty"` + Tags []string `json:"tags,omitempty"` + EventWebhooksUrl *string `json:"event_webhooks_url,omitempty"` + EventWebhooksStatus *application.ApplicationEventWebhookStatus `json:"event_webhooks_status,omitempty"` + EventWebhooksTypes []string `json:"event_webhooks_types,omitempty"` } func EditCurrentApplication(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, data EditCurrentApplicationData) (application.Application, error) { @@ -47,3 +52,17 @@ func EditCurrentApplication(ctx context.Context, token string, rateLimiter *rate err, _ := endpoint.Request(ctx, token, data, &app) return app, err } + +func GetActivityInstance(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId uint64, instanceId string) (application.ActivityInstance, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/applications/%d/activity-instances/%s", applicationId, instanceId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteGetActivityInstance, applicationId), + RateLimiter: rateLimiter, + } + + var instance application.ActivityInstance + err, _ := endpoint.Request(ctx, token, nil, &instance) + return instance, err +} diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index 4ec1bb4..ca7c654 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -219,6 +219,7 @@ const ( // /applications/@me RouteGetCurrentApplication RouteEditCurrentApplication + RouteGetActivityInstance ///applications/:id/entitlements RouteListEntitlements From aa19167c966a04d9e5851d7ad00e050dc5a25da9 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:12:18 +0100 Subject: [PATCH 57/73] Support after param and validate audit log limit Add an After field to GetGuildAuditLogData and include the 'after' query parameter when non-zero to support pagination. Make Limit optional (omitted if 0) and only include it in the query when its value is between 1 and 100; previously invalid limits were coerced to 50 and always sent. This prevents sending invalid limit values and aligns query behavior with API expectations. https://docs.discord.com/developers/resources/audit-log --- rest/auditlog.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rest/auditlog.go b/rest/auditlog.go index 4a5ddfd..a8e47dd 100644 --- a/rest/auditlog.go +++ b/rest/auditlog.go @@ -15,7 +15,8 @@ type GetGuildAuditLogData struct { UserId uint64 ActionType auditlog.AuditLogEvent Before uint64 // audit log entry ID - Limit int + After uint64 // audit log entry ID + Limit int // 1-100, omitted if 0 } func (d *GetGuildAuditLogData) Query() string { @@ -33,10 +34,13 @@ func (d *GetGuildAuditLogData) Query() string { query.Set("before", strconv.FormatUint(d.Before, 10)) } - if d.Limit > 100 || d.Limit < 1 { - d.Limit = 50 + if d.After != 0 { + query.Set("after", strconv.FormatUint(d.After, 10)) + } + + if d.Limit >= 1 && d.Limit <= 100 { + query.Set("limit", strconv.Itoa(d.Limit)) } - query.Set("limit", strconv.Itoa(d.Limit)) return query.Encode() } From 8c3fd5293dbe1802e93c3fe14f3306b96508f174 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:13:39 +0100 Subject: [PATCH 58/73] Add application emoji endpoints; fix content-type Add support for application-scoped emojis: list, get, create, modify and delete in rest/emojis.go (including ListApplicationEmojisResponse and CreateApplicationEmojiData with image encoding). Fix ModifyGuildEmoji to use application/json content type. Add corresponding route constants for application emoji endpoints in rest/ratelimit/routes.go so the rate limiter can handle these new routes. https://docs.discord.com/developers/resources/emoji --- rest/emojis.go | 94 +++++++++++++++++++++++++++++++++++++++- rest/ratelimit/routes.go | 7 +++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/rest/emojis.go b/rest/emojis.go index d027d4b..be8a490 100644 --- a/rest/emojis.go +++ b/rest/emojis.go @@ -79,7 +79,7 @@ func CreateGuildEmoji(ctx context.Context, token string, rateLimiter *ratelimit. func ModifyGuildEmoji(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, emojiId uint64, data CreateEmojiData) (emoji.Emoji, error) { endpoint := request.Endpoint{ RequestType: request.PATCH, - ContentType: request.Nil, + ContentType: request.ApplicationJson, Endpoint: fmt.Sprintf("/guilds/%d/emojis/%d", guildId, emojiId), Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyGuildEmoji, guildId), RateLimiter: rateLimiter, @@ -110,3 +110,95 @@ func DeleteGuildEmoji(ctx context.Context, token string, rateLimiter *ratelimit. err, _ := endpoint.Request(ctx, token, nil, nil) return err } + +type ListApplicationEmojisResponse struct { + Items []emoji.Emoji `json:"items"` +} + +func ListApplicationEmojis(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId uint64) ([]emoji.Emoji, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/applications/%d/emojis", applicationId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteListApplicationEmojis, applicationId), + RateLimiter: rateLimiter, + } + + var res ListApplicationEmojisResponse + err, _ := endpoint.Request(ctx, token, nil, &res) + return res.Items, err +} + +func GetApplicationEmoji(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, emojiId uint64) (emoji.Emoji, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/applications/%d/emojis/%d", applicationId, emojiId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteGetApplicationEmoji, applicationId), + RateLimiter: rateLimiter, + } + + var e emoji.Emoji + err, _ := endpoint.Request(ctx, token, nil, &e) + return e, err +} + +type CreateApplicationEmojiData struct { + Name string `json:"name"` + Image Image `json:"-"` +} + +func CreateApplicationEmoji(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId uint64, data CreateApplicationEmojiData) (emoji.Emoji, error) { + endpoint := request.Endpoint{ + RequestType: request.POST, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/applications/%d/emojis", applicationId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteCreateApplicationEmoji, applicationId), + RateLimiter: rateLimiter, + } + + var e emoji.Emoji + imageData, err := data.Image.Encode() + if err != nil { + return e, err + } + + body := map[string]interface{}{ + "name": data.Name, + "image": imageData, + } + + err, _ = endpoint.Request(ctx, token, body, &e) + return e, err +} + +func ModifyApplicationEmoji(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, emojiId uint64, name string) (emoji.Emoji, error) { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/applications/%d/emojis/%d", applicationId, emojiId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteModifyApplicationEmoji, applicationId), + RateLimiter: rateLimiter, + } + + body := map[string]interface{}{ + "name": name, + } + + var e emoji.Emoji + err, _ := endpoint.Request(ctx, token, body, &e) + return e, err +} + +func DeleteApplicationEmoji(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, emojiId uint64) error { + endpoint := request.Endpoint{ + RequestType: request.DELETE, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/applications/%d/emojis/%d", applicationId, emojiId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteDeleteApplicationEmoji, applicationId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, nil, nil) + return err +} diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index ca7c654..ad166b8 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -98,6 +98,13 @@ const ( RouteModifyGuildEmoji RouteDeleteGuildEmoji + // /applications/:id/emojis + RouteListApplicationEmojis + RouteGetApplicationEmoji + RouteCreateApplicationEmoji + RouteModifyApplicationEmoji + RouteDeleteApplicationEmoji + // /guilds/:id/... RouteCreateGuild RouteGetGuild From 41470cb7013f6254ce38e9704ebcdb536d46ab14 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:14:15 +0100 Subject: [PATCH 59/73] entitlement: add GetEntitlement and option fixes Add GetEntitlement API call and route constant; fix/query improvements and parameter renames for entitlements. Changes include: add RouteGetEntitlement; implement GetEntitlement endpoint; rename EntitlementQueryOptions fields (ExcludedEnded -> ExcludeEnded, add ExcludeDeleted) and update query param keys to exclude_ended/exclude_deleted; fix SKU list encoding to avoid trailing comma; switch several endpoints to request.Nil content type; simplify request return handling; correct rateLimiter/variable name typos. https://docs.discord.com/developers/resources/entitlement --- rest/entitlement.go | 66 ++++++++++++++++++++++++---------------- rest/ratelimit/routes.go | 1 + 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/rest/entitlement.go b/rest/entitlement.go index eb7f958..d17d042 100644 --- a/rest/entitlement.go +++ b/rest/entitlement.go @@ -4,7 +4,7 @@ import ( "context" "fmt" "net/url" - strconv "strconv" + "strconv" "github.com/TicketsBot-cloud/gdl/objects/entitlement" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" @@ -12,13 +12,14 @@ import ( ) type EntitlementQueryOptions struct { - UserId *uint64 - SkuIds []uint64 - Before *uint64 - After *uint64 - Limit *int - GuildId *uint64 - ExcludedEnded *bool + UserId *uint64 + SkuIds []uint64 + Before *uint64 + After *uint64 + Limit *int + GuildId *uint64 + ExcludeEnded *bool + ExcludeDeleted *bool } func (o *EntitlementQueryOptions) Query() string { @@ -31,13 +32,11 @@ func (o *EntitlementQueryOptions) Query() string { if len(o.SkuIds) > 0 { var encoded string for i, id := range o.SkuIds { - encoded += strconv.FormatUint(id, 10) + "," - - if i == len(o.SkuIds)-1 { - encoded = encoded[:len(encoded)-1] + encoded += strconv.FormatUint(id, 10) + if i < len(o.SkuIds)-1 { + encoded += "," } } - query.Add("sku_ids", encoded) } @@ -57,8 +56,12 @@ func (o *EntitlementQueryOptions) Query() string { query.Add("guild_id", strconv.FormatUint(*o.GuildId, 10)) } - if o.ExcludedEnded != nil { - query.Add("excluded_ended", strconv.FormatBool(*o.ExcludedEnded)) + if o.ExcludeEnded != nil { + query.Add("exclude_ended", strconv.FormatBool(*o.ExcludeEnded)) + } + + if o.ExcludeDeleted != nil { + query.Add("exclude_deleted", strconv.FormatBool(*o.ExcludeDeleted)) } return query.Encode() @@ -81,20 +84,31 @@ func ListEntitlements(ctx context.Context, token string, rateLimiter *ratelimit. return entitlements, nil } +func GetEntitlement(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, entitlementId uint64) (entitlement.Entitlement, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/applications/%d/entitlements/%d", applicationId, entitlementId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteGetEntitlement, applicationId), + RateLimiter: rateLimiter, + } + + var e entitlement.Entitlement + err, _ := endpoint.Request(ctx, token, nil, &e) + return e, err +} + func ConsumeEntitlement(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, entitlementId uint64) error { endpoint := request.Endpoint{ RequestType: request.POST, - ContentType: request.ApplicationJson, + ContentType: request.Nil, Endpoint: fmt.Sprintf("/applications/%d/entitlements/%d/consume", applicationId, entitlementId), Route: ratelimit.NewApplicationRoute(ratelimit.RouteConsumeEntitlement, applicationId), RateLimiter: rateLimiter, } - if err, _ := endpoint.Request(ctx, token, nil, nil); err != nil { - return err - } - - return nil + err, _ := endpoint.Request(ctx, token, nil, nil) + return err } type CreateTestEntitlementData struct { @@ -119,21 +133,21 @@ func CreateTestEntitlement(ctx context.Context, token string, rateLimiter *ratel RateLimiter: rateLimiter, } - var createdEntitlement entitlement.Entitlement - if err, _ := endpoint.Request(ctx, token, data, &createdEntitlement); err != nil { + var e entitlement.Entitlement + if err, _ := endpoint.Request(ctx, token, data, &e); err != nil { return entitlement.Entitlement{}, err } - return createdEntitlement, nil + return e, nil } -func DeleteTestEntitlement(ctx context.Context, token string, rateLimtier *ratelimit.Ratelimiter, applicationId, entitlementId uint64) error { +func DeleteTestEntitlement(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId, entitlementId uint64) error { endpoint := request.Endpoint{ RequestType: request.DELETE, ContentType: request.Nil, Endpoint: fmt.Sprintf("/applications/%d/entitlements/%d", applicationId, entitlementId), Route: ratelimit.NewApplicationRoute(ratelimit.RouteDeleteTestEntitlement, applicationId), - RateLimiter: rateLimtier, + RateLimiter: rateLimiter, } err, _ := endpoint.Request(ctx, token, nil, nil) diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index ad166b8..9e00058 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -230,6 +230,7 @@ const ( ///applications/:id/entitlements RouteListEntitlements + RouteGetEntitlement RouteConsumeEntitlement RouteCreateTestEntitlement RouteDeleteTestEntitlement From 9dc74f32959a69fb0626b917118bf6ca442cbe26 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:14:55 +0100 Subject: [PATCH 60/73] Support guild_scheduled_event_id in GetInvite Add an optional guildScheduledEventId (*uint64) parameter to GetInvite and append guild_scheduled_event_id to the /invites/{code} query when provided. The endpoint URL is now built in a variable to include with_counts and the optional scheduled event id. Also simplified DeleteInvite endpoint construction by using string concatenation. https://docs.discord.com/developers/resources/invite --- rest/invite.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/rest/invite.go b/rest/invite.go index 311ad92..690abe8 100644 --- a/rest/invite.go +++ b/rest/invite.go @@ -9,11 +9,16 @@ import ( "github.com/TicketsBot-cloud/gdl/rest/request" ) -func GetInvite(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, inviteCode string, withCounts bool) (invite.Invite, error) { +func GetInvite(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, inviteCode string, withCounts bool, guildScheduledEventId *uint64) (invite.Invite, error) { + url := fmt.Sprintf("/invites/%s?with_counts=%v", inviteCode, withCounts) + if guildScheduledEventId != nil { + url += fmt.Sprintf("&guild_scheduled_event_id=%d", *guildScheduledEventId) + } + endpoint := request.Endpoint{ RequestType: request.GET, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/invites/%s?with_counts=%v", inviteCode, withCounts), + Endpoint: url, Route: ratelimit.NewGuildRoute(ratelimit.RouteGetInvite, 0), // No ratelimit RateLimiter: rateLimiter, } @@ -27,7 +32,7 @@ func DeleteInvite(ctx context.Context, token string, rateLimiter *ratelimit.Rate endpoint := request.Endpoint{ RequestType: request.DELETE, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/invites/%s", inviteCode), + Endpoint: "/invites/" + inviteCode, Route: ratelimit.NewGuildRoute(ratelimit.RouteDeleteInvite, 0), // No ratelimit RateLimiter: rateLimiter, } From a61962e84348f21cb7ae6162926584e844618bc6 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:15:40 +0100 Subject: [PATCH 61/73] Add voice state REST endpoints Add support for guild voice state operations. Introduces new rate-limit route constants and implements GetCurrentUserVoiceState, GetUserVoiceState, ModifyCurrentUserVoiceState, and ModifyUserVoiceState in rest/voice.go, including request payload structs and a time import. These use the ratelimiter and request.Endpoint to call the /guilds/:id/voice-states endpoints. https://docs.discord.com/developers/resources/voice --- rest/ratelimit/routes.go | 6 ++++ rest/voice.go | 68 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index 9e00058..2da80b0 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -173,6 +173,12 @@ const ( // /voice/regions RouteListVoiceRegions + // /guilds/:id/voice-states + RouteGetCurrentUserVoiceState + RouteGetUserVoiceState + RouteModifyCurrentUserVoiceState + RouteModifyUserVoiceState + // /channels/:id/webhooks RouteCreateWebhook RouteGetChannelWebhooks diff --git a/rest/voice.go b/rest/voice.go index 0dea5dd..e53bd62 100644 --- a/rest/voice.go +++ b/rest/voice.go @@ -3,6 +3,7 @@ package rest import ( "context" "fmt" + "time" "github.com/TicketsBot-cloud/gdl/objects/guild" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" @@ -13,7 +14,7 @@ func ListVoiceRegions(ctx context.Context, token string) ([]guild.VoiceRegion, e endpoint := request.Endpoint{ RequestType: request.GET, ContentType: request.Nil, - Endpoint: fmt.Sprintf("/voice/regions"), + Endpoint: "/voice/regions", Route: ratelimit.NewOtherRoute(ratelimit.RouteListVoiceRegions, 0), } @@ -21,3 +22,68 @@ func ListVoiceRegions(ctx context.Context, token string) ([]guild.VoiceRegion, e err, _ := endpoint.Request(ctx, token, nil, &voiceRegions) return voiceRegions, err } + +func GetCurrentUserVoiceState(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) (guild.VoiceState, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/voice-states/@me", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetCurrentUserVoiceState, guildId), + RateLimiter: rateLimiter, + } + + var state guild.VoiceState + err, _ := endpoint.Request(ctx, token, nil, &state) + return state, err +} + +func GetUserVoiceState(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, userId uint64) (guild.VoiceState, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/voice-states/%d", guildId, userId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetUserVoiceState, guildId), + RateLimiter: rateLimiter, + } + + var state guild.VoiceState + err, _ := endpoint.Request(ctx, token, nil, &state) + return state, err +} + +type ModifyCurrentUserVoiceStateData struct { + ChannelId *uint64 `json:"channel_id,string,omitempty"` + Suppress *bool `json:"suppress,omitempty"` + RequestToSpeakTimestamp *time.Time `json:"request_to_speak_timestamp,omitempty"` +} + +func ModifyCurrentUserVoiceState(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data ModifyCurrentUserVoiceStateData) error { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/voice-states/@me", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyCurrentUserVoiceState, guildId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, data, nil) + return err +} + +type ModifyUserVoiceStateData struct { + ChannelId *uint64 `json:"channel_id,string,omitempty"` + Suppress *bool `json:"suppress,omitempty"` +} + +func ModifyUserVoiceState(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, userId uint64, data ModifyUserVoiceStateData) error { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/voice-states/%d", guildId, userId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyUserVoiceState, guildId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, data, nil) + return err +} From ec329667b32c0683b4d82d733a474d50c101a27f Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:16:29 +0100 Subject: [PATCH 62/73] Add /oauth2/@me endpoint and client_credentials grant Introduce support for the GET /oauth2/@me endpoint by adding an AuthorizationInformation struct and GetCurrentAuthorizationInformation helper that requests bearer-token-only authorization info (application, scopes, expires time and optional user). Also add the GrantTypeClientCredentials constant and a corresponding rate limit route constant for the new endpoint. https://docs.discord.com/developers/topics/oauth2 --- rest/oauth.go | 27 +++++++++++++++++++++++++++ rest/ratelimit/routes.go | 1 + 2 files changed, 28 insertions(+) diff --git a/rest/oauth.go b/rest/oauth.go index 89be734..1922953 100644 --- a/rest/oauth.go +++ b/rest/oauth.go @@ -6,7 +6,10 @@ import ( "encoding/json" "errors" "fmt" + "time" + "github.com/TicketsBot-cloud/gdl/objects/application" + "github.com/TicketsBot-cloud/gdl/objects/user" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" "github.com/TicketsBot-cloud/gdl/rest/request" ) @@ -40,6 +43,7 @@ type ( const ( GrantTypeAuthorizationCode GrantType = "authorization_code" GrantTypeRefreshToken GrantType = "refresh_token" + GrantTypeClientCredentials GrantType = "client_credentials" TokenTypeHintAccessToken TokenTypeHint = "access_token" TokenTypeHintRefreshToken TokenTypeHint = "refresh_token" @@ -106,6 +110,29 @@ func RevokeToken(ctx context.Context, rateLimiter *ratelimit.Ratelimiter, client return convertToOauthError(err) } +// AuthorizationInformation is returned by GET /oauth2/@me (bearer token only). +type AuthorizationInformation struct { + Application application.Application `json:"application"` + Scopes []string `json:"scopes"` + Expires time.Time `json:"expires"` + User *user.User `json:"user,omitempty"` +} + +// GetCurrentAuthorizationInformation requires a bearer token, not a bot token. +func GetCurrentAuthorizationInformation(ctx context.Context, bearerToken string, rateLimiter *ratelimit.Ratelimiter) (AuthorizationInformation, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: "/oauth2/@me", + Route: ratelimit.NewOtherRoute(ratelimit.RouteGetCurrentAuthorizationInformation, 0), + RateLimiter: rateLimiter, + } + + var info AuthorizationInformation + err, _ := endpoint.Request(ctx, "Bearer "+bearerToken, nil, &info) + return info, err +} + func convertToOauthError(err error) error { var restError request.RestError if errors.As(err, &restError) { diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index 2da80b0..702e869 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -244,4 +244,5 @@ const ( // /oauth2/ RouteOauth2TokenExchange RouteOauth2TokenRevoke + RouteGetCurrentAuthorizationInformation ) From 61d530e9a3e2dddd8990128eae80d25ca4b9bc5b Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:17:01 +0100 Subject: [PATCH 63/73] Use io.ReadAll instead of ioutil.ReadAll Replace the deprecated ioutil.ReadAll call with io.ReadAll and remove the unused ioutil import in rest/image.go. This updates the code to the Go 1.16+ standard library usage and removes an unused import. --- rest/image.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rest/image.go b/rest/image.go index a2bbf38..e8d7ff5 100644 --- a/rest/image.go +++ b/rest/image.go @@ -4,7 +4,6 @@ import ( "encoding/base64" "fmt" "io" - "io/ioutil" "github.com/TicketsBot-cloud/gdl/rest/request" ) @@ -15,7 +14,7 @@ type Image struct { } func (i *Image) Encode() (string, error) { - content, err := ioutil.ReadAll(i.ImageReader) + content, err := io.ReadAll(i.ImageReader) if err != nil { return "", err } From a76e78a77d3dcfb1f603c8f779eae77d0b16997f Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 17:40:46 +0100 Subject: [PATCH 64/73] Adjust REST ListThreadMembers and object types Pass an empty ListThreadMembersData to the updated rest.ListThreadMembers signature in gateway/restwrapper.go. Tighten up object definitions: use concrete GuildScheduledEvent type in AuditLog, reformat and add TriggeringInteractionMetadata to MessageInteractionMetadata, and mark VoiceState.Member as omitempty to avoid emitting empty member objects. These changes align structs with updated API payloads and function signatures. --- gateway/restwrapper.go | 2 +- objects/auditlog/auditlog.go | 17 +++++++++-------- objects/channel/message/messageinteraction.go | 17 +++++++++-------- objects/guild/voicestate.go | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/gateway/restwrapper.go b/gateway/restwrapper.go index 248526a..d53b631 100644 --- a/gateway/restwrapper.go +++ b/gateway/restwrapper.go @@ -187,7 +187,7 @@ func (s *Shard) GetThreadMember(ctx context.Context, channelId, userId uint64) ( } func (s *Shard) ListThreadMembers(ctx context.Context, channelId uint64) ([]channel.ThreadMember, error) { - return rest.ListThreadMembers(ctx, s.Token, s.ShardManager.RateLimiter, channelId) + return rest.ListThreadMembers(ctx, s.Token, s.ShardManager.RateLimiter, channelId, rest.ListThreadMembersData{}) } func (s *Shard) ListActiveThreads(ctx context.Context, guildId uint64) (rest.ThreadsResponse, error) { diff --git a/objects/auditlog/auditlog.go b/objects/auditlog/auditlog.go index 337b9a2..b078394 100644 --- a/objects/auditlog/auditlog.go +++ b/objects/auditlog/auditlog.go @@ -4,18 +4,19 @@ import ( "github.com/TicketsBot-cloud/gdl/objects/automoderation" "github.com/TicketsBot-cloud/gdl/objects/channel" "github.com/TicketsBot-cloud/gdl/objects/guild" + "github.com/TicketsBot-cloud/gdl/objects/guild/scheduledevent" "github.com/TicketsBot-cloud/gdl/objects/integration" "github.com/TicketsBot-cloud/gdl/objects/interaction" "github.com/TicketsBot-cloud/gdl/objects/user" ) type AuditLog struct { - ApplicationCommands []interaction.ApplicationCommand `json:"application_commands"` - AutoModerationRules []automoderation.Rule `json:"auto_moderation_rules"` - Entries []AuditLogEntry `json:"audit_log_entries"` - GuildScheduledEvents []interface{} `json:"guild_scheduled_events"` - Integrations []integration.Integration `json:"integrations"` - Threads []channel.Channel `json:"threads"` - Users []user.User `json:"users"` - Webhooks []guild.Webhook `json:"webhooks"` + ApplicationCommands []interaction.ApplicationCommand `json:"application_commands"` + AutoModerationRules []automoderation.Rule `json:"auto_moderation_rules"` + Entries []AuditLogEntry `json:"audit_log_entries"` + GuildScheduledEvents []scheduledevent.GuildScheduledEvent `json:"guild_scheduled_events"` + Integrations []integration.Integration `json:"integrations"` + Threads []channel.Channel `json:"threads"` + Users []user.User `json:"users"` + Webhooks []guild.Webhook `json:"webhooks"` } diff --git a/objects/channel/message/messageinteraction.go b/objects/channel/message/messageinteraction.go index 3018156..56c5324 100644 --- a/objects/channel/message/messageinteraction.go +++ b/objects/channel/message/messageinteraction.go @@ -15,12 +15,13 @@ type MessageInteraction struct { } type MessageInteractionMetadata struct { - Id uint64 `json:"id,string"` - Type int `json:"type"` - User user.User `json:"user"` - AuthorizingIntegrationOwners map[string]string `json:"authorizing_integration_owners"` - OriginalResponseMessageId *uint64 `json:"original_response_message_id,string,omitempty"` - TargetUser *user.User `json:"target_user,omitempty"` - TargetMessageId *uint64 `json:"target_message_id,string,omitempty"` - InteractedMessageId *uint64 `json:"interacted_message_id,string,omitempty"` + Id uint64 `json:"id,string"` + Type int `json:"type"` + User user.User `json:"user"` + AuthorizingIntegrationOwners map[string]string `json:"authorizing_integration_owners"` + OriginalResponseMessageId *uint64 `json:"original_response_message_id,string,omitempty"` + TargetUser *user.User `json:"target_user,omitempty"` + TargetMessageId *uint64 `json:"target_message_id,string,omitempty"` + InteractedMessageId *uint64 `json:"interacted_message_id,string,omitempty"` + TriggeringInteractionMetadata *MessageInteractionMetadata `json:"triggering_interaction_metadata,omitempty"` } diff --git a/objects/guild/voicestate.go b/objects/guild/voicestate.go index 173325a..f1a07fd 100644 --- a/objects/guild/voicestate.go +++ b/objects/guild/voicestate.go @@ -10,7 +10,7 @@ type VoiceState struct { GuildId *uint64 `json:"guild_id,string"` ChannelId *uint64 `json:"channel_id,string"` UserId uint64 `json:"user_id,string"` - Member *member.Member `json:"member"` + Member *member.Member `json:"member,omitempty"` SessionId string `json:"session_id"` Deaf bool `json:"deaf"` Mute bool `json:"mute"` From 3c1a6fd599f9db623d16a5f9454ac3fa61d16b00 Mon Sep 17 00:00:00 2001 From: biast12 Date: Wed, 4 Mar 2026 21:00:59 +0100 Subject: [PATCH 65/73] Add new REST endpoints and SKU object Introduce multiple new REST handlers and types to support additional Discord API features: auto-moderation, scheduled events, polls, soundboard, stage instances, stickers, subscriptions, and SKU listing. Add objects/sku SKU type and flags. Update ratelimit route enums and gateway restwrapper calls (BeginGuildPrune signature, GetInvite, GetGlobalCommands, GetGuildCommands) and add guild welcome screen and AddGuildMember helpers. These changes extend API coverage for newer endpoints and wire them into the existing rate limiter/request system. --- gateway/restwrapper.go | 11 ++- objects/sku/sku.go | 27 ++++++ rest/automoderation.go | 110 +++++++++++++++++++++++++ rest/guild.go | 65 +++++++++++++++ rest/poll.go | 70 ++++++++++++++++ rest/ratelimit/routes.go | 55 +++++++++++++ rest/scheduledevent.go | 172 +++++++++++++++++++++++++++++++++++++++ rest/sku.go | 27 ++++++ rest/soundboard.go | 138 +++++++++++++++++++++++++++++++ rest/stage.go | 84 +++++++++++++++++++ rest/sticker.go | 136 +++++++++++++++++++++++++++++++ rest/subscription.go | 72 ++++++++++++++++ 12 files changed, 963 insertions(+), 4 deletions(-) create mode 100644 objects/sku/sku.go create mode 100644 rest/automoderation.go create mode 100644 rest/poll.go create mode 100644 rest/scheduledevent.go create mode 100644 rest/sku.go create mode 100644 rest/soundboard.go create mode 100644 rest/stage.go create mode 100644 rest/sticker.go create mode 100644 rest/subscription.go diff --git a/gateway/restwrapper.go b/gateway/restwrapper.go index d53b631..43d8cef 100644 --- a/gateway/restwrapper.go +++ b/gateway/restwrapper.go @@ -511,7 +511,10 @@ func (s *Shard) GetGuildPruneCount(ctx context.Context, guildId uint64, days int // computePruneCount = whether 'pruned' is returned, discouraged for large guilds func (s *Shard) BeginGuildPrune(ctx context.Context, guildId uint64, days int, computePruneCount bool) error { - return rest.BeginGuildPrune(ctx, s.Token, s.ShardManager.RateLimiter, guildId, days, computePruneCount) + return rest.BeginGuildPrune(ctx, s.Token, s.ShardManager.RateLimiter, guildId, rest.BeginGuildPruneData{ + Days: days, + ComputePruneCount: computePruneCount, + }) } func (s *Shard) GetGuildVoiceRegions(ctx context.Context, guildId uint64) ([]guild.VoiceRegion, error) { @@ -556,7 +559,7 @@ func (s *Shard) GetGuildVanityUrl(ctx context.Context, guildId uint64) (invite.I } func (s *Shard) GetInvite(ctx context.Context, inviteCode string, withCounts bool) (invite.Invite, error) { - return rest.GetInvite(ctx, s.Token, s.ShardManager.RateLimiter, inviteCode, withCounts) + return rest.GetInvite(ctx, s.Token, s.ShardManager.RateLimiter, inviteCode, withCounts, nil) } func (s *Shard) DeleteInvite(ctx context.Context, inviteCode string) (invite.Invite, error) { @@ -668,7 +671,7 @@ func (s *Shard) GetGuildAuditLog(ctx context.Context, guildId uint64, data rest. } func (s *Shard) GetGlobalCommands(ctx context.Context, applicationId uint64) ([]interaction.ApplicationCommand, error) { - return rest.GetGlobalCommands(ctx, s.Token, s.ShardManager.RateLimiter, applicationId) + return rest.GetGlobalCommands(ctx, s.Token, s.ShardManager.RateLimiter, applicationId, false) } func (s *Shard) CreateGlobalCommand(ctx context.Context, applicationId uint64, data rest.CreateCommandData) (interaction.ApplicationCommand, error) { @@ -688,7 +691,7 @@ func (s *Shard) DeleteGlobalCommand(ctx context.Context, applicationId, commandI } func (s *Shard) GetGuildCommands(ctx context.Context, applicationId, guildId uint64) ([]interaction.ApplicationCommand, error) { - return rest.GetGuildCommands(ctx, s.Token, s.ShardManager.RateLimiter, applicationId, guildId) + return rest.GetGuildCommands(ctx, s.Token, s.ShardManager.RateLimiter, applicationId, guildId, false) } func (s *Shard) CreateGuildCommand(ctx context.Context, applicationId, guildId uint64, data rest.CreateCommandData) (interaction.ApplicationCommand, error) { diff --git a/objects/sku/sku.go b/objects/sku/sku.go new file mode 100644 index 0000000..d5ead40 --- /dev/null +++ b/objects/sku/sku.go @@ -0,0 +1,27 @@ +package sku + +type SKUType int + +const ( + SKUTypeDurable SKUType = 2 + SKUTypeConsumable SKUType = 3 + SKUTypeSubscription SKUType = 5 + SKUTypeSubscriptionGroup SKUType = 6 +) + +type SKUFlag uint32 + +const ( + SKUFlagAvailable SKUFlag = 1 << 2 + SKUFlagGuildSubscription SKUFlag = 1 << 7 + SKUFlagUserSubscription SKUFlag = 1 << 8 +) + +type SKU struct { + Id uint64 `json:"id,string"` + Type SKUType `json:"type"` + ApplicationId uint64 `json:"application_id,string"` + Name string `json:"name"` + Slug string `json:"slug"` + Flags SKUFlag `json:"flags"` +} diff --git a/rest/automoderation.go b/rest/automoderation.go new file mode 100644 index 0000000..1ebbbe0 --- /dev/null +++ b/rest/automoderation.go @@ -0,0 +1,110 @@ +package rest + +import ( + "context" + "fmt" + + "github.com/TicketsBot-cloud/gdl/objects/automoderation" + "github.com/TicketsBot-cloud/gdl/rest/ratelimit" + "github.com/TicketsBot-cloud/gdl/rest/request" + "github.com/TicketsBot-cloud/gdl/utils" +) + +type CreateAutoModerationRuleData struct { + Name string `json:"name"` + EventType automoderation.EventType `json:"event_type"` + TriggerType automoderation.TriggerType `json:"trigger_type"` + TriggerMetadata *automoderation.TriggerMetadata `json:"trigger_metadata,omitempty"` + Actions []automoderation.Action `json:"actions"` + Enabled *bool `json:"enabled,omitempty"` + ExemptRoles utils.Uint64StringSlice `json:"exempt_roles,omitempty"` + ExemptChannels utils.Uint64StringSlice `json:"exempt_channels,omitempty"` +} + +type ModifyAutoModerationRuleData struct { + Name *string `json:"name,omitempty"` + EventType *automoderation.EventType `json:"event_type,omitempty"` + TriggerMetadata *automoderation.TriggerMetadata `json:"trigger_metadata,omitempty"` + Actions []automoderation.Action `json:"actions,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + ExemptRoles utils.Uint64StringSlice `json:"exempt_roles,omitempty"` + ExemptChannels utils.Uint64StringSlice `json:"exempt_channels,omitempty"` +} + +func ListAutoModerationRules(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) ([]automoderation.Rule, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/auto-moderation/rules", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteListAutoModerationRules, guildId), + RateLimiter: rateLimiter, + } + + var rules []automoderation.Rule + if err, _ := endpoint.Request(ctx, token, nil, &rules); err != nil { + return nil, err + } + + return rules, nil +} + +func GetAutoModerationRule(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, ruleId uint64) (automoderation.Rule, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/auto-moderation/rules/%d", guildId, ruleId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetAutoModerationRule, guildId), + RateLimiter: rateLimiter, + } + + var rule automoderation.Rule + err, _ := endpoint.Request(ctx, token, nil, &rule) + return rule, err +} + +func CreateAutoModerationRule(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data CreateAutoModerationRuleData) (automoderation.Rule, error) { + endpoint := request.Endpoint{ + RequestType: request.POST, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/auto-moderation/rules", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteCreateAutoModerationRule, guildId), + RateLimiter: rateLimiter, + } + + var rule automoderation.Rule + if err, _ := endpoint.Request(ctx, token, data, &rule); err != nil { + return automoderation.Rule{}, err + } + + return rule, nil +} + +func ModifyAutoModerationRule(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, ruleId uint64, data ModifyAutoModerationRuleData) (automoderation.Rule, error) { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/auto-moderation/rules/%d", guildId, ruleId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyAutoModerationRule, guildId), + RateLimiter: rateLimiter, + } + + var rule automoderation.Rule + if err, _ := endpoint.Request(ctx, token, data, &rule); err != nil { + return automoderation.Rule{}, err + } + + return rule, nil +} + +func DeleteAutoModerationRule(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, ruleId uint64) error { + endpoint := request.Endpoint{ + RequestType: request.DELETE, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/auto-moderation/rules/%d", guildId, ruleId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteDeleteAutoModerationRule, guildId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, nil, nil) + return err +} diff --git a/rest/guild.go b/rest/guild.go index 8d447ea..53fd292 100644 --- a/rest/guild.go +++ b/rest/guild.go @@ -712,3 +712,68 @@ func GetGuildVanityURL(ctx context.Context, token string, rateLimiter *ratelimit err, _ = endpoint.Request(ctx, token, nil, &invite) return } + +type AddGuildMemberData struct { + AccessToken string `json:"access_token"` + Nick *string `json:"nick,omitempty"` + Roles utils.Uint64StringSlice `json:"roles,omitempty"` + Mute *bool `json:"mute,omitempty"` + Deaf *bool `json:"deaf,omitempty"` +} + +// Returns nil if the user was already a member of the guild (HTTP 204). +func AddGuildMember(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, userId uint64, data AddGuildMemberData) (*member.Member, error) { + endpoint := request.Endpoint{ + RequestType: request.PUT, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/members/%d", guildId, userId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteAddGuildMember, guildId), + RateLimiter: rateLimiter, + } + + var m member.Member + if err, res := endpoint.Request(ctx, token, data, &m); err != nil { + return nil, err + } else if res != nil && res.StatusCode == 204 { + return nil, nil + } + + return &m, nil +} + +func GetGuildWelcomeScreen(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) (guild.WelcomeScreen, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/welcome-screen", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildWelcomeScreen, guildId), + RateLimiter: rateLimiter, + } + + var screen guild.WelcomeScreen + err, _ := endpoint.Request(ctx, token, nil, &screen) + return screen, err +} + +type ModifyGuildWelcomeScreenData struct { + Enabled *bool `json:"enabled,omitempty"` + WelcomeChannels []guild.WelcomeScreenChannel `json:"welcome_channels,omitempty"` + Description *string `json:"description,omitempty"` +} + +func ModifyGuildWelcomeScreen(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data ModifyGuildWelcomeScreenData) (guild.WelcomeScreen, error) { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/welcome-screen", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyGuildWelcomeScreen, guildId), + RateLimiter: rateLimiter, + } + + var screen guild.WelcomeScreen + if err, _ := endpoint.Request(ctx, token, data, &screen); err != nil { + return guild.WelcomeScreen{}, err + } + + return screen, nil +} diff --git a/rest/poll.go b/rest/poll.go new file mode 100644 index 0000000..27147cf --- /dev/null +++ b/rest/poll.go @@ -0,0 +1,70 @@ +package rest + +import ( + "context" + "fmt" + "net/url" + "strconv" + + "github.com/TicketsBot-cloud/gdl/objects/channel/message" + "github.com/TicketsBot-cloud/gdl/objects/user" + "github.com/TicketsBot-cloud/gdl/rest/ratelimit" + "github.com/TicketsBot-cloud/gdl/rest/request" +) + +type GetPollAnswerVotersData struct { + After *uint64 + Limit *int +} + +func (d *GetPollAnswerVotersData) Query() string { + query := url.Values{} + + if d.After != nil { + query.Add("after", strconv.FormatUint(*d.After, 10)) + } + + if d.Limit != nil { + query.Add("limit", strconv.Itoa(*d.Limit)) + } + + return query.Encode() +} + +type pollAnswerVotersResponse struct { + Users []user.User `json:"users"` +} + +func GetPollAnswerVoters(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId, messageId uint64, answerId int, data GetPollAnswerVotersData) ([]user.User, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/channels/%d/polls/%d/answers/%d?%s", channelId, messageId, answerId, data.Query()), + Route: ratelimit.NewChannelRoute(ratelimit.RouteGetPollAnswerVoters, channelId), + RateLimiter: rateLimiter, + } + + var res pollAnswerVotersResponse + if err, _ := endpoint.Request(ctx, token, nil, &res); err != nil { + return nil, err + } + + return res.Users, nil +} + +func EndPoll(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId, messageId uint64) (message.Message, error) { + endpoint := request.Endpoint{ + RequestType: request.POST, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/channels/%d/polls/%d/expire", channelId, messageId), + Route: ratelimit.NewChannelRoute(ratelimit.RouteEndPoll, channelId), + RateLimiter: rateLimiter, + } + + var msg message.Message + if err, _ := endpoint.Request(ctx, token, nil, &msg); err != nil { + return message.Message{}, err + } + + return msg, nil +} diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index 702e869..97179fc 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -245,4 +245,59 @@ const ( RouteOauth2TokenExchange RouteOauth2TokenRevoke RouteGetCurrentAuthorizationInformation + + // Auto Moderation + RouteListAutoModerationRules + RouteGetAutoModerationRule + RouteCreateAutoModerationRule + RouteModifyAutoModerationRule + RouteDeleteAutoModerationRule + + // Guild Scheduled Events + RouteListGuildScheduledEvents + RouteGetGuildScheduledEvent + RouteCreateGuildScheduledEvent + RouteModifyGuildScheduledEvent + RouteDeleteGuildScheduledEvent + RouteGetGuildScheduledEventUsers + + // Stage Instances + RouteCreateStageInstance + RouteGetStageInstance + RouteModifyStageInstance + RouteDeleteStageInstance + + // Soundboard + RouteSendSoundboardSound + RouteGetDefaultSoundboardSounds + RouteListGuildSoundboardSounds + RouteGetGuildSoundboardSound + RouteCreateGuildSoundboardSound + RouteModifyGuildSoundboardSound + RouteDeleteGuildSoundboardSound + + // Polls + RouteGetPollAnswerVoters + RouteEndPoll + + // SKUs + RouteListSKUs + + // Subscriptions + RouteListSKUSubscriptions + RouteGetSKUSubscription + + // Stickers + RouteGetSticker + RouteGetStickerPacks + RouteGetStickerPack + RouteListGuildStickers + RouteGetGuildSticker + RouteCreateGuildSticker + RouteModifyGuildSticker + RouteDeleteGuildSticker + + // Guild Welcome Screen + RouteGetGuildWelcomeScreen + RouteModifyGuildWelcomeScreen ) diff --git a/rest/scheduledevent.go b/rest/scheduledevent.go new file mode 100644 index 0000000..e12e047 --- /dev/null +++ b/rest/scheduledevent.go @@ -0,0 +1,172 @@ +package rest + +import ( + "context" + "fmt" + "net/url" + "strconv" + "time" + + "github.com/TicketsBot-cloud/gdl/objects/guild/scheduledevent" + "github.com/TicketsBot-cloud/gdl/objects/member" + "github.com/TicketsBot-cloud/gdl/objects/user" + "github.com/TicketsBot-cloud/gdl/rest/ratelimit" + "github.com/TicketsBot-cloud/gdl/rest/request" +) + +type CreateGuildScheduledEventData struct { + ChannelId *uint64 `json:"channel_id,string,omitempty"` + EntityMetadata *scheduledevent.EntityMetadata `json:"entity_metadata,omitempty"` + Name string `json:"name"` + PrivacyLevel scheduledevent.PrivacyLevel `json:"privacy_level"` + ScheduledStartTime time.Time `json:"scheduled_start_time"` + ScheduledEndTime *time.Time `json:"scheduled_end_time,omitempty"` + Description *string `json:"description,omitempty"` + EntityType scheduledevent.EntityType `json:"entity_type"` + Image *string `json:"image,omitempty"` + RecurrenceRule *scheduledevent.RecurrenceRule `json:"recurrence_rule,omitempty"` +} + +type ModifyGuildScheduledEventData struct { + ChannelId *uint64 `json:"channel_id,string,omitempty"` + EntityMetadata *scheduledevent.EntityMetadata `json:"entity_metadata,omitempty"` + Name *string `json:"name,omitempty"` + PrivacyLevel *scheduledevent.PrivacyLevel `json:"privacy_level,omitempty"` + ScheduledStartTime *time.Time `json:"scheduled_start_time,omitempty"` + ScheduledEndTime *time.Time `json:"scheduled_end_time,omitempty"` + Description *string `json:"description,omitempty"` + EntityType *scheduledevent.EntityType `json:"entity_type,omitempty"` + Status *scheduledevent.Status `json:"status,omitempty"` + Image *string `json:"image,omitempty"` + RecurrenceRule *scheduledevent.RecurrenceRule `json:"recurrence_rule,omitempty"` +} + +type GetGuildScheduledEventUsersData struct { + Limit *int + WithMember *bool + Before *uint64 + After *uint64 +} + +func (d *GetGuildScheduledEventUsersData) Query() string { + query := url.Values{} + + if d.Limit != nil { + query.Add("limit", strconv.Itoa(*d.Limit)) + } + + if d.WithMember != nil { + query.Add("with_member", strconv.FormatBool(*d.WithMember)) + } + + if d.Before != nil { + query.Add("before", strconv.FormatUint(*d.Before, 10)) + } + + if d.After != nil { + query.Add("after", strconv.FormatUint(*d.After, 10)) + } + + return query.Encode() +} + +type GuildScheduledEventUser struct { + GuildScheduledEventId uint64 `json:"guild_scheduled_event_id,string"` + User user.User `json:"user"` + Member *member.Member `json:"member,omitempty"` +} + +func ListGuildScheduledEvents(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, withUserCount bool) ([]scheduledevent.GuildScheduledEvent, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/scheduled-events?with_user_count=%s", guildId, strconv.FormatBool(withUserCount)), + Route: ratelimit.NewGuildRoute(ratelimit.RouteListGuildScheduledEvents, guildId), + RateLimiter: rateLimiter, + } + + var events []scheduledevent.GuildScheduledEvent + if err, _ := endpoint.Request(ctx, token, nil, &events); err != nil { + return nil, err + } + + return events, nil +} + +func GetGuildScheduledEvent(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, eventId uint64, withUserCount bool) (scheduledevent.GuildScheduledEvent, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/scheduled-events/%d?with_user_count=%s", guildId, eventId, strconv.FormatBool(withUserCount)), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildScheduledEvent, guildId), + RateLimiter: rateLimiter, + } + + var event scheduledevent.GuildScheduledEvent + err, _ := endpoint.Request(ctx, token, nil, &event) + return event, err +} + +func CreateGuildScheduledEvent(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data CreateGuildScheduledEventData) (scheduledevent.GuildScheduledEvent, error) { + endpoint := request.Endpoint{ + RequestType: request.POST, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/scheduled-events", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteCreateGuildScheduledEvent, guildId), + RateLimiter: rateLimiter, + } + + var event scheduledevent.GuildScheduledEvent + if err, _ := endpoint.Request(ctx, token, data, &event); err != nil { + return scheduledevent.GuildScheduledEvent{}, err + } + + return event, nil +} + +func ModifyGuildScheduledEvent(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, eventId uint64, data ModifyGuildScheduledEventData) (scheduledevent.GuildScheduledEvent, error) { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/scheduled-events/%d", guildId, eventId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyGuildScheduledEvent, guildId), + RateLimiter: rateLimiter, + } + + var event scheduledevent.GuildScheduledEvent + if err, _ := endpoint.Request(ctx, token, data, &event); err != nil { + return scheduledevent.GuildScheduledEvent{}, err + } + + return event, nil +} + +func DeleteGuildScheduledEvent(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, eventId uint64) error { + endpoint := request.Endpoint{ + RequestType: request.DELETE, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/scheduled-events/%d", guildId, eventId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteDeleteGuildScheduledEvent, guildId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, nil, nil) + return err +} + +func GetGuildScheduledEventUsers(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, eventId uint64, data GetGuildScheduledEventUsersData) ([]GuildScheduledEventUser, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/scheduled-events/%d/users?%s", guildId, eventId, data.Query()), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildScheduledEventUsers, guildId), + RateLimiter: rateLimiter, + } + + var users []GuildScheduledEventUser + if err, _ := endpoint.Request(ctx, token, nil, &users); err != nil { + return nil, err + } + + return users, nil +} diff --git a/rest/sku.go b/rest/sku.go new file mode 100644 index 0000000..241cd09 --- /dev/null +++ b/rest/sku.go @@ -0,0 +1,27 @@ +package rest + +import ( + "context" + "fmt" + + "github.com/TicketsBot-cloud/gdl/objects/sku" + "github.com/TicketsBot-cloud/gdl/rest/ratelimit" + "github.com/TicketsBot-cloud/gdl/rest/request" +) + +func ListSKUs(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, applicationId uint64) ([]sku.SKU, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/applications/%d/skus", applicationId), + Route: ratelimit.NewApplicationRoute(ratelimit.RouteListSKUs, applicationId), + RateLimiter: rateLimiter, + } + + var skus []sku.SKU + if err, _ := endpoint.Request(ctx, token, nil, &skus); err != nil { + return nil, err + } + + return skus, nil +} diff --git a/rest/soundboard.go b/rest/soundboard.go new file mode 100644 index 0000000..fa54e87 --- /dev/null +++ b/rest/soundboard.go @@ -0,0 +1,138 @@ +package rest + +import ( + "context" + "fmt" + + "github.com/TicketsBot-cloud/gdl/objects/soundboard" + "github.com/TicketsBot-cloud/gdl/rest/ratelimit" + "github.com/TicketsBot-cloud/gdl/rest/request" +) + +type SendSoundboardSoundData struct { + SoundId uint64 `json:"sound_id,string"` + SourceGuildId *uint64 `json:"source_guild_id,string,omitempty"` +} + +type CreateGuildSoundboardSoundData struct { + Name string `json:"name"` + Sound string `json:"sound"` + Volume *float64 `json:"volume,omitempty"` + EmojiId *uint64 `json:"emoji_id,string,omitempty"` + EmojiName *string `json:"emoji_name,omitempty"` +} + +type ModifyGuildSoundboardSoundData struct { + Name *string `json:"name,omitempty"` + Volume *float64 `json:"volume,omitempty"` + EmojiId *uint64 `json:"emoji_id,string,omitempty"` + EmojiName *string `json:"emoji_name,omitempty"` +} + +func SendSoundboardSound(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64, data SendSoundboardSoundData) error { + endpoint := request.Endpoint{ + RequestType: request.POST, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/channels/%d/send-soundboard-sound", channelId), + Route: ratelimit.NewChannelRoute(ratelimit.RouteSendSoundboardSound, channelId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, data, nil) + return err +} + +func GetDefaultSoundboardSounds(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter) ([]soundboard.SoundboardSound, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: "/soundboard-default-sounds", + Route: ratelimit.NewOtherRoute(ratelimit.RouteGetDefaultSoundboardSounds, 0), + RateLimiter: rateLimiter, + } + + var sounds []soundboard.SoundboardSound + if err, _ := endpoint.Request(ctx, token, nil, &sounds); err != nil { + return nil, err + } + + return sounds, nil +} + +func ListGuildSoundboardSounds(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) ([]soundboard.SoundboardSound, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/soundboard-sounds", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteListGuildSoundboardSounds, guildId), + RateLimiter: rateLimiter, + } + + var sounds []soundboard.SoundboardSound + if err, _ := endpoint.Request(ctx, token, nil, &sounds); err != nil { + return nil, err + } + + return sounds, nil +} + +func GetGuildSoundboardSound(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, soundId uint64) (soundboard.SoundboardSound, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/soundboard-sounds/%d", guildId, soundId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildSoundboardSound, guildId), + RateLimiter: rateLimiter, + } + + var sound soundboard.SoundboardSound + err, _ := endpoint.Request(ctx, token, nil, &sound) + return sound, err +} + +func CreateGuildSoundboardSound(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data CreateGuildSoundboardSoundData) (soundboard.SoundboardSound, error) { + endpoint := request.Endpoint{ + RequestType: request.POST, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/soundboard-sounds", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteCreateGuildSoundboardSound, guildId), + RateLimiter: rateLimiter, + } + + var sound soundboard.SoundboardSound + if err, _ := endpoint.Request(ctx, token, data, &sound); err != nil { + return soundboard.SoundboardSound{}, err + } + + return sound, nil +} + +func ModifyGuildSoundboardSound(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, soundId uint64, data ModifyGuildSoundboardSoundData) (soundboard.SoundboardSound, error) { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/soundboard-sounds/%d", guildId, soundId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyGuildSoundboardSound, guildId), + RateLimiter: rateLimiter, + } + + var sound soundboard.SoundboardSound + if err, _ := endpoint.Request(ctx, token, data, &sound); err != nil { + return soundboard.SoundboardSound{}, err + } + + return sound, nil +} + +func DeleteGuildSoundboardSound(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, soundId uint64) error { + endpoint := request.Endpoint{ + RequestType: request.DELETE, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/soundboard-sounds/%d", guildId, soundId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteDeleteGuildSoundboardSound, guildId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, nil, nil) + return err +} diff --git a/rest/stage.go b/rest/stage.go new file mode 100644 index 0000000..563a889 --- /dev/null +++ b/rest/stage.go @@ -0,0 +1,84 @@ +package rest + +import ( + "context" + "fmt" + + "github.com/TicketsBot-cloud/gdl/objects/stage" + "github.com/TicketsBot-cloud/gdl/rest/ratelimit" + "github.com/TicketsBot-cloud/gdl/rest/request" +) + +type CreateStageInstanceData struct { + ChannelId uint64 `json:"channel_id,string"` + Topic string `json:"topic"` + PrivacyLevel *stage.StagePrivacyLevel `json:"privacy_level,omitempty"` + SendStartNotification *bool `json:"send_start_notification,omitempty"` + GuildScheduledEventId *uint64 `json:"guild_scheduled_event_id,string,omitempty"` +} + +type ModifyStageInstanceData struct { + Topic *string `json:"topic,omitempty"` + PrivacyLevel *stage.StagePrivacyLevel `json:"privacy_level,omitempty"` +} + +func CreateStageInstance(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, data CreateStageInstanceData) (stage.StageInstance, error) { + endpoint := request.Endpoint{ + RequestType: request.POST, + ContentType: request.ApplicationJson, + Endpoint: "/stage-instances", + Route: ratelimit.NewChannelRoute(ratelimit.RouteCreateStageInstance, data.ChannelId), + RateLimiter: rateLimiter, + } + + var instance stage.StageInstance + if err, _ := endpoint.Request(ctx, token, data, &instance); err != nil { + return stage.StageInstance{}, err + } + + return instance, nil +} + +func GetStageInstance(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64) (stage.StageInstance, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/stage-instances/%d", channelId), + Route: ratelimit.NewChannelRoute(ratelimit.RouteGetStageInstance, channelId), + RateLimiter: rateLimiter, + } + + var instance stage.StageInstance + err, _ := endpoint.Request(ctx, token, nil, &instance) + return instance, err +} + +func ModifyStageInstance(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64, data ModifyStageInstanceData) (stage.StageInstance, error) { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/stage-instances/%d", channelId), + Route: ratelimit.NewChannelRoute(ratelimit.RouteModifyStageInstance, channelId), + RateLimiter: rateLimiter, + } + + var instance stage.StageInstance + if err, _ := endpoint.Request(ctx, token, data, &instance); err != nil { + return stage.StageInstance{}, err + } + + return instance, nil +} + +func DeleteStageInstance(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, channelId uint64) error { + endpoint := request.Endpoint{ + RequestType: request.DELETE, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/stage-instances/%d", channelId), + Route: ratelimit.NewChannelRoute(ratelimit.RouteDeleteStageInstance, channelId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, nil, nil) + return err +} diff --git a/rest/sticker.go b/rest/sticker.go new file mode 100644 index 0000000..7b65050 --- /dev/null +++ b/rest/sticker.go @@ -0,0 +1,136 @@ +package rest + +import ( + "context" + "fmt" + + "github.com/TicketsBot-cloud/gdl/objects/guild/sticker" + "github.com/TicketsBot-cloud/gdl/rest/ratelimit" + "github.com/TicketsBot-cloud/gdl/rest/request" +) + +type ModifyGuildStickerData struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + Tags *string `json:"tags,omitempty"` +} + +type StickerPack struct { + Id uint64 `json:"id,string"` + Stickers []sticker.Sticker `json:"stickers"` + Name string `json:"name"` + SkuId uint64 `json:"sku_id,string"` + CoverStickerId *uint64 `json:"cover_sticker_id,string,omitempty"` + Description string `json:"description"` + BannerAssetId *uint64 `json:"banner_asset_id,string,omitempty"` +} + +func GetSticker(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, stickerId uint64) (sticker.Sticker, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/stickers/%d", stickerId), + Route: ratelimit.NewOtherRoute(ratelimit.RouteGetSticker, stickerId), + RateLimiter: rateLimiter, + } + + var s sticker.Sticker + err, _ := endpoint.Request(ctx, token, nil, &s) + return s, err +} + +type stickerPacksResponse struct { + StickerPacks []StickerPack `json:"sticker_packs"` +} + +func GetStickerPacks(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter) ([]StickerPack, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: "/sticker-packs", + Route: ratelimit.NewOtherRoute(ratelimit.RouteGetStickerPacks, 0), + RateLimiter: rateLimiter, + } + + var res stickerPacksResponse + if err, _ := endpoint.Request(ctx, token, nil, &res); err != nil { + return nil, err + } + + return res.StickerPacks, nil +} + +func GetStickerPack(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, packId uint64) (StickerPack, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/sticker-packs/%d", packId), + Route: ratelimit.NewOtherRoute(ratelimit.RouteGetStickerPack, packId), + RateLimiter: rateLimiter, + } + + var pack StickerPack + err, _ := endpoint.Request(ctx, token, nil, &pack) + return pack, err +} + +func ListGuildStickers(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64) ([]sticker.Sticker, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/stickers", guildId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteListGuildStickers, guildId), + RateLimiter: rateLimiter, + } + + var stickers []sticker.Sticker + if err, _ := endpoint.Request(ctx, token, nil, &stickers); err != nil { + return nil, err + } + + return stickers, nil +} + +func GetGuildSticker(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, stickerId uint64) (sticker.Sticker, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/stickers/%d", guildId, stickerId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteGetGuildSticker, guildId), + RateLimiter: rateLimiter, + } + + var s sticker.Sticker + err, _ := endpoint.Request(ctx, token, nil, &s) + return s, err +} + +func ModifyGuildSticker(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, stickerId uint64, data ModifyGuildStickerData) (sticker.Sticker, error) { + endpoint := request.Endpoint{ + RequestType: request.PATCH, + ContentType: request.ApplicationJson, + Endpoint: fmt.Sprintf("/guilds/%d/stickers/%d", guildId, stickerId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteModifyGuildSticker, guildId), + RateLimiter: rateLimiter, + } + + var s sticker.Sticker + if err, _ := endpoint.Request(ctx, token, data, &s); err != nil { + return sticker.Sticker{}, err + } + + return s, nil +} + +func DeleteGuildSticker(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId, stickerId uint64) error { + endpoint := request.Endpoint{ + RequestType: request.DELETE, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/stickers/%d", guildId, stickerId), + Route: ratelimit.NewGuildRoute(ratelimit.RouteDeleteGuildSticker, guildId), + RateLimiter: rateLimiter, + } + + err, _ := endpoint.Request(ctx, token, nil, nil) + return err +} diff --git a/rest/subscription.go b/rest/subscription.go new file mode 100644 index 0000000..8c2e25b --- /dev/null +++ b/rest/subscription.go @@ -0,0 +1,72 @@ +package rest + +import ( + "context" + "fmt" + "net/url" + "strconv" + + "github.com/TicketsBot-cloud/gdl/objects/subscription" + "github.com/TicketsBot-cloud/gdl/rest/ratelimit" + "github.com/TicketsBot-cloud/gdl/rest/request" +) + +type ListSKUSubscriptionsData struct { + Before *uint64 + After *uint64 + Limit *int + UserId *uint64 +} + +func (d *ListSKUSubscriptionsData) Query() string { + query := url.Values{} + + if d.Before != nil { + query.Add("before", strconv.FormatUint(*d.Before, 10)) + } + + if d.After != nil { + query.Add("after", strconv.FormatUint(*d.After, 10)) + } + + if d.Limit != nil { + query.Add("limit", strconv.Itoa(*d.Limit)) + } + + if d.UserId != nil { + query.Add("user_id", strconv.FormatUint(*d.UserId, 10)) + } + + return query.Encode() +} + +func ListSKUSubscriptions(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, skuId uint64, data ListSKUSubscriptionsData) ([]subscription.Subscription, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/skus/%d/subscriptions?%s", skuId, data.Query()), + Route: ratelimit.NewOtherRoute(ratelimit.RouteListSKUSubscriptions, skuId), + RateLimiter: rateLimiter, + } + + var subscriptions []subscription.Subscription + if err, _ := endpoint.Request(ctx, token, nil, &subscriptions); err != nil { + return nil, err + } + + return subscriptions, nil +} + +func GetSKUSubscription(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, skuId, subscriptionId uint64) (subscription.Subscription, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/skus/%d/subscriptions/%d", skuId, subscriptionId), + Route: ratelimit.NewOtherRoute(ratelimit.RouteGetSKUSubscription, skuId), + RateLimiter: rateLimiter, + } + + var sub subscription.Subscription + err, _ := endpoint.Request(ctx, token, nil, &sub) + return sub, err +} From d1935ef232696b1faa996eb38b42933f582be245 Mon Sep 17 00:00:00 2001 From: biast12 Date: Thu, 5 Mar 2026 00:24:20 +0100 Subject: [PATCH 66/73] Move guild objects and rename event file Reorganize object packages by moving soundboard and stage into objects/guild and update all affected imports. Rename gateway/payloads/events/eventtypes.go to registry.go and adjust references in gateway payloads and REST clients (gateway/payloads/events/guildsoundboard.go, gateway/payloads/events/stageinstances.go, rest/soundboard.go, rest/stage.go) to use the new paths. --- gateway/payloads/events/guildsoundboard.go | 2 +- gateway/payloads/events/{eventtypes.go => registry.go} | 0 gateway/payloads/events/stageinstances.go | 2 +- objects/{ => guild}/soundboard/soundboard.go | 0 objects/{ => guild}/stage/stage.go | 0 rest/soundboard.go | 2 +- rest/stage.go | 2 +- 7 files changed, 4 insertions(+), 4 deletions(-) rename gateway/payloads/events/{eventtypes.go => registry.go} (100%) rename objects/{ => guild}/soundboard/soundboard.go (100%) rename objects/{ => guild}/stage/stage.go (100%) diff --git a/gateway/payloads/events/guildsoundboard.go b/gateway/payloads/events/guildsoundboard.go index 786a7a6..9f55e42 100644 --- a/gateway/payloads/events/guildsoundboard.go +++ b/gateway/payloads/events/guildsoundboard.go @@ -1,6 +1,6 @@ package events -import "github.com/TicketsBot-cloud/gdl/objects/soundboard" +import "github.com/TicketsBot-cloud/gdl/objects/guild/soundboard" type GuildSoundboardSoundCreate struct { soundboard.SoundboardSound diff --git a/gateway/payloads/events/eventtypes.go b/gateway/payloads/events/registry.go similarity index 100% rename from gateway/payloads/events/eventtypes.go rename to gateway/payloads/events/registry.go diff --git a/gateway/payloads/events/stageinstances.go b/gateway/payloads/events/stageinstances.go index aca5772..88494de 100644 --- a/gateway/payloads/events/stageinstances.go +++ b/gateway/payloads/events/stageinstances.go @@ -1,6 +1,6 @@ package events -import "github.com/TicketsBot-cloud/gdl/objects/stage" +import "github.com/TicketsBot-cloud/gdl/objects/guild/stage" type StageInstanceCreate struct { stage.StageInstance diff --git a/objects/soundboard/soundboard.go b/objects/guild/soundboard/soundboard.go similarity index 100% rename from objects/soundboard/soundboard.go rename to objects/guild/soundboard/soundboard.go diff --git a/objects/stage/stage.go b/objects/guild/stage/stage.go similarity index 100% rename from objects/stage/stage.go rename to objects/guild/stage/stage.go diff --git a/rest/soundboard.go b/rest/soundboard.go index fa54e87..ebb59bc 100644 --- a/rest/soundboard.go +++ b/rest/soundboard.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/TicketsBot-cloud/gdl/objects/soundboard" + "github.com/TicketsBot-cloud/gdl/objects/guild/soundboard" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" "github.com/TicketsBot-cloud/gdl/rest/request" ) diff --git a/rest/stage.go b/rest/stage.go index 563a889..08227a0 100644 --- a/rest/stage.go +++ b/rest/stage.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/TicketsBot-cloud/gdl/objects/stage" + "github.com/TicketsBot-cloud/gdl/objects/guild/stage" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" "github.com/TicketsBot-cloud/gdl/rest/request" ) From 4cb5c58901a5c9cddc5d3a38b56e8a8ebc221696 Mon Sep 17 00:00:00 2001 From: biast12 Date: Fri, 6 Mar 2026 18:42:43 +0100 Subject: [PATCH 67/73] Use iota for enum constants Replace hardcoded numeric enum values with iota across many object packages. Constants were converted to use iota (with iota+N and blank identifiers where needed to preserve offsets) and large const blocks were reorganized (notably auditlog). Affected files include application, automoderation, channel, guild, integration, interaction, invite, sku, auditlog, and related enums. This refactor simplifies enum maintenance without changing intended numeric values. --- objects/application/application.go | 10 +- objects/application/team.go | 4 +- objects/auditlog/auditlogevent.go | 177 +++++++++++------- objects/automoderation/automoderation.go | 29 +-- objects/channel/channeltype.go | 29 +-- .../channel/message/messageactivitytype.go | 9 +- objects/channel/permissionoverwritetype.go | 4 +- .../guild/defaultmessagenotificationlevel.go | 4 +- objects/guild/explicitcontentfilterlevel.go | 6 +- objects/guild/stage/stage.go | 4 +- objects/guild/verificationlevel.go | 10 +- objects/guild/webhooktype.go | 6 +- objects/integration/connection.go | 4 +- .../integration/integrationexpirebehaviour.go | 4 +- objects/interaction/applicationcommand.go | 4 +- objects/interaction/interactioncontext.go | 6 +- objects/invite/invite.go | 10 +- objects/sku/sku.go | 10 +- 18 files changed, 190 insertions(+), 140 deletions(-) diff --git a/objects/application/application.go b/objects/application/application.go index 7b3a1d5..71270ba 100644 --- a/objects/application/application.go +++ b/objects/application/application.go @@ -42,16 +42,16 @@ type Application struct { type ApplicationEventWebhookStatus int const ( - ApplicationEventWebhookStatusDisabled ApplicationEventWebhookStatus = 1 - ApplicationEventWebhookStatusEnabled ApplicationEventWebhookStatus = 2 - ApplicationEventWebhookStatusDisabledByDiscord ApplicationEventWebhookStatus = 3 + ApplicationEventWebhookStatusDisabled ApplicationEventWebhookStatus = iota + 1 + ApplicationEventWebhookStatusEnabled + ApplicationEventWebhookStatusDisabledByDiscord ) type ApplicationIntegrationType int const ( - ApplicationIntegrationTypeGuildInstall ApplicationIntegrationType = 0 - ApplicationIntegrationTypeUserInstall ApplicationIntegrationType = 1 + ApplicationIntegrationTypeGuildInstall ApplicationIntegrationType = iota + ApplicationIntegrationTypeUserInstall ) type ApplicationIntegrationTypeConfig struct { diff --git a/objects/application/team.go b/objects/application/team.go index 6265df4..a317ee4 100644 --- a/objects/application/team.go +++ b/objects/application/team.go @@ -24,8 +24,8 @@ type ( ) const ( - TeamMembershipStateInvited TeamMembershipState = 1 - TeamMembershipStateAccepted TeamMembershipState = 2 + TeamMembershipStateInvited TeamMembershipState = iota + 1 + TeamMembershipStateAccepted TeamMemberRoleOwner TeamMemberRole = "owner" TeamMemberRoleAdmin TeamMemberRole = "admin" diff --git a/objects/auditlog/auditlogevent.go b/objects/auditlog/auditlogevent.go index 3fa234f..37b1a98 100644 --- a/objects/auditlog/auditlogevent.go +++ b/objects/auditlog/auditlogevent.go @@ -3,78 +3,121 @@ package auditlog type AuditLogEvent int const ( - AuditLogEventGuildUpdate AuditLogEvent = 1 - AuditLogEventChannelCreate AuditLogEvent = 10 - AuditLogEventChannelUpdate AuditLogEvent = 11 - AuditLogEventChannelDelete AuditLogEvent = 12 - AuditLogEventChannelOverwriteCreate AuditLogEvent = 13 - AuditLogEventChannelOverwriteUpdate AuditLogEvent = 14 - AuditLogEventChannelOverwriteDelete AuditLogEvent = 15 - AuditLogEventMemberKick AuditLogEvent = 20 - AuditLogEventMemberPrune AuditLogEvent = 21 - AuditLogEventMemberBanAdd AuditLogEvent = 22 - AuditLogEventMemberBanRemove AuditLogEvent = 23 - AuditLogEventMemberUpdate AuditLogEvent = 24 - AuditLogEventMemberRoleUpdate AuditLogEvent = 25 - AuditLogEventMemberMove AuditLogEvent = 26 - AuditLogEventMemberDisconnect AuditLogEvent = 27 - AuditLogEventBotAdd AuditLogEvent = 28 - AuditLogEventRoleCreate AuditLogEvent = 30 - AuditLogEventRoleUpdate AuditLogEvent = 31 - AuditLogEventRoleDelete AuditLogEvent = 32 - AuditLogEventInviteCreate AuditLogEvent = 40 - AuditLogEventInviteUpdate AuditLogEvent = 41 - AuditLogEventInviteDelete AuditLogEvent = 42 - AuditLogEventWebhookCreate AuditLogEvent = 50 - AuditLogEventWebhookUpdate AuditLogEvent = 51 - AuditLogEventWebhookDelete AuditLogEvent = 52 - AuditLogEventEmojiCreate AuditLogEvent = 60 - AuditLogEventEmojiUpdate AuditLogEvent = 61 - AuditLogEventEmojiDelete AuditLogEvent = 62 - AuditLogEventMessageDelete AuditLogEvent = 72 - AuditLogEventMessageBulkDelete AuditLogEvent = 73 - AuditLogEventMessagePin AuditLogEvent = 74 - AuditLogEventMessageUnpin AuditLogEvent = 75 - AuditLogEventIntegrationCreate AuditLogEvent = 80 - AuditLogEventIntegrationUpdate AuditLogEvent = 81 - AuditLogEventIntegrationDelete AuditLogEvent = 82 - AuditLogEventStageInstanceCreate AuditLogEvent = 83 - AuditLogEventStageInstanceUpdate AuditLogEvent = 84 - AuditLogEventStageInstanceDelete AuditLogEvent = 85 - AuditLogEventStickerCreate AuditLogEvent = 90 - AuditLogEventStickerUpdate AuditLogEvent = 91 - AuditLogEventStickerDelete AuditLogEvent = 92 - - AuditLogEventGuildScheduledEventCreate AuditLogEvent = 100 - AuditLogEventGuildScheduledEventUpdate AuditLogEvent = 101 - AuditLogEventGuildScheduledEventDelete AuditLogEvent = 102 - - AuditLogEventThreadCreate AuditLogEvent = 110 - AuditLogEventThreadUpdate AuditLogEvent = 111 - AuditLogEventThreadDelete AuditLogEvent = 112 + AuditLogEventGuildUpdate AuditLogEvent = 1 +) + +const ( + AuditLogEventChannelCreate AuditLogEvent = iota + 10 + AuditLogEventChannelUpdate + AuditLogEventChannelDelete + AuditLogEventChannelOverwriteCreate + AuditLogEventChannelOverwriteUpdate + AuditLogEventChannelOverwriteDelete +) + +const ( + AuditLogEventMemberKick AuditLogEvent = iota + 20 + AuditLogEventMemberPrune + AuditLogEventMemberBanAdd + AuditLogEventMemberBanRemove + AuditLogEventMemberUpdate + AuditLogEventMemberRoleUpdate + AuditLogEventMemberMove + AuditLogEventMemberDisconnect + AuditLogEventBotAdd +) + +const ( + AuditLogEventRoleCreate AuditLogEvent = iota + 30 + AuditLogEventRoleUpdate + AuditLogEventRoleDelete +) +const ( + AuditLogEventInviteCreate AuditLogEvent = iota + 40 + AuditLogEventInviteUpdate + AuditLogEventInviteDelete +) + +const ( + AuditLogEventWebhookCreate AuditLogEvent = iota + 50 + AuditLogEventWebhookUpdate + AuditLogEventWebhookDelete +) + +const ( + AuditLogEventEmojiCreate AuditLogEvent = iota + 60 + AuditLogEventEmojiUpdate + AuditLogEventEmojiDelete +) + +const ( + AuditLogEventMessageDelete AuditLogEvent = iota + 72 + AuditLogEventMessageBulkDelete + AuditLogEventMessagePin + AuditLogEventMessageUnpin +) + +const ( + AuditLogEventIntegrationCreate AuditLogEvent = iota + 80 + AuditLogEventIntegrationUpdate + AuditLogEventIntegrationDelete + AuditLogEventStageInstanceCreate + AuditLogEventStageInstanceUpdate + AuditLogEventStageInstanceDelete +) + +const ( + AuditLogEventStickerCreate AuditLogEvent = iota + 90 + AuditLogEventStickerUpdate + AuditLogEventStickerDelete +) + +const ( + AuditLogEventGuildScheduledEventCreate AuditLogEvent = iota + 100 + AuditLogEventGuildScheduledEventUpdate + AuditLogEventGuildScheduledEventDelete +) + +const ( + AuditLogEventThreadCreate AuditLogEvent = iota + 110 + AuditLogEventThreadUpdate + AuditLogEventThreadDelete +) + +const ( AuditLogEventApplicationCommandPermissionUpdate AuditLogEvent = 121 +) - AuditLogEventSoundboardSoundCreate AuditLogEvent = 130 - AuditLogEventSoundboardSoundUpdate AuditLogEvent = 131 - AuditLogEventSoundboardSoundDelete AuditLogEvent = 132 +const ( + AuditLogEventSoundboardSoundCreate AuditLogEvent = iota + 130 + AuditLogEventSoundboardSoundUpdate + AuditLogEventSoundboardSoundDelete +) - AuditLogEventAutoModerationRuleCreate AuditLogEvent = 140 - AuditLogEventAutoModerationRuleUpdate AuditLogEvent = 141 - AuditLogEventAutoModerationRuleDelete AuditLogEvent = 142 - AuditLogEventAutoModerationBlockMessage AuditLogEvent = 143 - AuditLogEventAutoModerationFlagToChannel AuditLogEvent = 144 - AuditLogEventAutoModerationUserCommunicationDis AuditLogEvent = 145 +const ( + AuditLogEventAutoModerationRuleCreate AuditLogEvent = iota + 140 + AuditLogEventAutoModerationRuleUpdate + AuditLogEventAutoModerationRuleDelete + AuditLogEventAutoModerationBlockMessage + AuditLogEventAutoModerationFlagToChannel + AuditLogEventAutoModerationUserCommunicationDis +) - AuditLogEventCreatorMonetizationRequestCreated AuditLogEvent = 150 - AuditLogEventCreatorMonetizationTermsAccepted AuditLogEvent = 151 +const ( + AuditLogEventCreatorMonetizationRequestCreated AuditLogEvent = iota + 150 + AuditLogEventCreatorMonetizationTermsAccepted +) - AuditLogEventOnboardingPromptCreate AuditLogEvent = 163 - AuditLogEventOnboardingPromptUpdate AuditLogEvent = 164 - AuditLogEventOnboardingPromptDelete AuditLogEvent = 165 - AuditLogEventOnboardingCreate AuditLogEvent = 166 - AuditLogEventOnboardingUpdate AuditLogEvent = 167 +const ( + AuditLogEventOnboardingPromptCreate AuditLogEvent = iota + 163 + AuditLogEventOnboardingPromptUpdate + AuditLogEventOnboardingPromptDelete + AuditLogEventOnboardingCreate + AuditLogEventOnboardingUpdate +) - AuditLogEventHomeSettingsCreate AuditLogEvent = 190 - AuditLogEventHomeSettingsUpdate AuditLogEvent = 191 +const ( + AuditLogEventHomeSettingsCreate AuditLogEvent = iota + 190 + AuditLogEventHomeSettingsUpdate ) diff --git a/objects/automoderation/automoderation.go b/objects/automoderation/automoderation.go index 7b54a17..cad9030 100644 --- a/objects/automoderation/automoderation.go +++ b/objects/automoderation/automoderation.go @@ -5,35 +5,36 @@ import "github.com/TicketsBot-cloud/gdl/utils" type EventType int const ( - EventTypeMessageSend EventType = 1 - EventTypeMemberUpdate EventType = 2 + EventTypeMessageSend EventType = iota + 1 + EventTypeMemberUpdate ) type TriggerType int const ( - TriggerTypeKeyword TriggerType = 1 - TriggerTypeSpam TriggerType = 3 - TriggerTypeKeywordPreset TriggerType = 4 - TriggerTypeMentionSpam TriggerType = 5 - TriggerTypeMemberProfile TriggerType = 6 + TriggerTypeKeyword TriggerType = iota + 1 + _ + TriggerTypeSpam + TriggerTypeKeywordPreset + TriggerTypeMentionSpam + TriggerTypeMemberProfile ) type KeywordPresetType int const ( - KeywordPresetTypeProfanity KeywordPresetType = 1 - KeywordPresetTypeSexualContent KeywordPresetType = 2 - KeywordPresetTypeSlurs KeywordPresetType = 3 + KeywordPresetTypeProfanity KeywordPresetType = iota + 1 + KeywordPresetTypeSexualContent + KeywordPresetTypeSlurs ) type ActionType int const ( - ActionTypeBlockMessage ActionType = 1 - ActionTypeSendAlertMessage ActionType = 2 - ActionTypeTimeout ActionType = 3 - ActionTypeBlockMemberInteraction ActionType = 4 + ActionTypeBlockMessage ActionType = iota + 1 + ActionTypeSendAlertMessage + ActionTypeTimeout + ActionTypeBlockMemberInteraction ) type TriggerMetadata struct { diff --git a/objects/channel/channeltype.go b/objects/channel/channeltype.go index 9074627..675428f 100644 --- a/objects/channel/channeltype.go +++ b/objects/channel/channeltype.go @@ -3,17 +3,20 @@ package channel type ChannelType int const ( - ChannelTypeGuildText ChannelType = 0 - ChannelTypeDM ChannelType = 1 - ChannelTypeGuildVoice ChannelType = 2 - ChannelTypeGroupDM ChannelType = 3 - ChannelTypeGuildCategory ChannelType = 4 - ChannelTypeGuildAnnouncement ChannelType = 5 - ChannelTypeAnnouncementThread ChannelType = 10 - ChannelTypePublicThread ChannelType = 11 - ChannelTypePrivateThread ChannelType = 12 - ChannelTypeGuildStageVoice ChannelType = 13 - ChannelTypeGuildDirectory ChannelType = 14 - ChannelTypeGuildForum ChannelType = 15 - ChannelTypeGuildMedia ChannelType = 16 + ChannelTypeGuildText ChannelType = iota + ChannelTypeDM + ChannelTypeGuildVoice + ChannelTypeGroupDM + ChannelTypeGuildCategory + ChannelTypeGuildAnnouncement +) + +const ( + ChannelTypeAnnouncementThread ChannelType = iota + 10 + ChannelTypePublicThread + ChannelTypePrivateThread + ChannelTypeGuildStageVoice + ChannelTypeGuildDirectory + ChannelTypeGuildForum + ChannelTypeGuildMedia ) diff --git a/objects/channel/message/messageactivitytype.go b/objects/channel/message/messageactivitytype.go index d414092..b42dd0b 100644 --- a/objects/channel/message/messageactivitytype.go +++ b/objects/channel/message/messageactivitytype.go @@ -3,8 +3,9 @@ package message type MessageActivityType int const ( - MessageActivityTypeJoin MessageActivityType = 1 - MessageActivityTypeSpectate MessageActivityType = 2 - MessageActivityTypeListen MessageActivityType = 3 - MessageActivityTypeJoinRequest MessageActivityType = 5 + MessageActivityTypeJoin MessageActivityType = iota + 1 + MessageActivityTypeSpectate + MessageActivityTypeListen + _ + MessageActivityTypeJoinRequest ) diff --git a/objects/channel/permissionoverwritetype.go b/objects/channel/permissionoverwritetype.go index 1be56a3..8d700dc 100644 --- a/objects/channel/permissionoverwritetype.go +++ b/objects/channel/permissionoverwritetype.go @@ -3,6 +3,6 @@ package channel type PermissionOverwriteType int const ( - PermissionOverwriteTypeRole PermissionOverwriteType = 0 - PermissionOverwriteTypeMember PermissionOverwriteType = 1 + PermissionOverwriteTypeRole PermissionOverwriteType = iota + PermissionOverwriteTypeMember ) diff --git a/objects/guild/defaultmessagenotificationlevel.go b/objects/guild/defaultmessagenotificationlevel.go index 3a17d1a..0edd318 100644 --- a/objects/guild/defaultmessagenotificationlevel.go +++ b/objects/guild/defaultmessagenotificationlevel.go @@ -3,6 +3,6 @@ package guild type DefaultMessageNotificationLevel int const ( - DefaultMessageNotificationLevelAllMessages DefaultMessageNotificationLevel = 0 - DefaultMessageNotificationLevelOnlyMentions DefaultMessageNotificationLevel = 1 + DefaultMessageNotificationLevelAllMessages DefaultMessageNotificationLevel = iota + DefaultMessageNotificationLevelOnlyMentions ) diff --git a/objects/guild/explicitcontentfilterlevel.go b/objects/guild/explicitcontentfilterlevel.go index 07e7138..34302f1 100644 --- a/objects/guild/explicitcontentfilterlevel.go +++ b/objects/guild/explicitcontentfilterlevel.go @@ -3,7 +3,7 @@ package guild type ExplicitContentFilterLevel int const ( - ExplicitContentFilterLevelDisabled ExplicitContentFilterLevel = 0 - ExplicitContentFilterLevelMembersWithoutRoles ExplicitContentFilterLevel = 1 - ExplicitContentFilterLevelAllMembers ExplicitContentFilterLevel = 2 + ExplicitContentFilterLevelDisabled ExplicitContentFilterLevel = iota + ExplicitContentFilterLevelMembersWithoutRoles + ExplicitContentFilterLevelAllMembers ) diff --git a/objects/guild/stage/stage.go b/objects/guild/stage/stage.go index 1406b6f..f24ab10 100644 --- a/objects/guild/stage/stage.go +++ b/objects/guild/stage/stage.go @@ -5,8 +5,8 @@ import "github.com/TicketsBot-cloud/gdl/objects" type StagePrivacyLevel int const ( - StagePrivacyLevelPublic StagePrivacyLevel = 1 // Deprecated - StagePrivacyLevelGuildOnly StagePrivacyLevel = 2 + StagePrivacyLevelPublic StagePrivacyLevel = iota + 1 // Deprecated + StagePrivacyLevelGuildOnly ) type StageInstance struct { diff --git a/objects/guild/verificationlevel.go b/objects/guild/verificationlevel.go index 5fab283..0a393ac 100644 --- a/objects/guild/verificationlevel.go +++ b/objects/guild/verificationlevel.go @@ -3,9 +3,9 @@ package guild type VerificationLevel int const ( - VerificationLevelNone VerificationLevel = 0 - VerificationLevelLow VerificationLevel = 1 - VerificationLevelMedium VerificationLevel = 2 - VerificationLevelHigh VerificationLevel = 3 - VerificationLevelVeryHigh VerificationLevel = 4 + VerificationLevelNone VerificationLevel = iota + VerificationLevelLow + VerificationLevelMedium + VerificationLevelHigh + VerificationLevelVeryHigh ) diff --git a/objects/guild/webhooktype.go b/objects/guild/webhooktype.go index eed070f..27ae972 100644 --- a/objects/guild/webhooktype.go +++ b/objects/guild/webhooktype.go @@ -3,7 +3,7 @@ package guild type WebhookType int const ( - WebhookTypeIncoming WebhookType = 1 - WebhookTypeChannelFollower WebhookType = 2 - WebhookTypeApplication WebhookType = 3 + WebhookTypeIncoming WebhookType = iota + 1 + WebhookTypeChannelFollower + WebhookTypeApplication ) diff --git a/objects/integration/connection.go b/objects/integration/connection.go index 1180642..62ea645 100644 --- a/objects/integration/connection.go +++ b/objects/integration/connection.go @@ -3,8 +3,8 @@ package integration type ConnectionVisibility int const ( - ConnectionVisibilityNone ConnectionVisibility = 0 - ConnectionVisibilityEveryone ConnectionVisibility = 1 + ConnectionVisibilityNone ConnectionVisibility = iota + ConnectionVisibilityEveryone ) type Connection struct { diff --git a/objects/integration/integrationexpirebehaviour.go b/objects/integration/integrationexpirebehaviour.go index b32bb64..514d729 100644 --- a/objects/integration/integrationexpirebehaviour.go +++ b/objects/integration/integrationexpirebehaviour.go @@ -3,6 +3,6 @@ package integration type IntegrationExpireBehaviour int const ( - IntegrationExpireBehaviourRemoveRole IntegrationExpireBehaviour = 0 - IntegrationExpireBehaviourKick IntegrationExpireBehaviour = 1 + IntegrationExpireBehaviourRemoveRole IntegrationExpireBehaviour = iota + IntegrationExpireBehaviourKick ) diff --git a/objects/interaction/applicationcommand.go b/objects/interaction/applicationcommand.go index 2f87192..68807a4 100644 --- a/objects/interaction/applicationcommand.go +++ b/objects/interaction/applicationcommand.go @@ -32,6 +32,6 @@ const ( type ApplicationCommandHandlerType uint8 const ( - ApplicationCommandHandlerTypeAppHandler ApplicationCommandHandlerType = 1 - ApplicationCommandHandlerTypeDiscordLaunchActivity ApplicationCommandHandlerType = 2 + ApplicationCommandHandlerTypeAppHandler ApplicationCommandHandlerType = iota + 1 + ApplicationCommandHandlerTypeDiscordLaunchActivity ) diff --git a/objects/interaction/interactioncontext.go b/objects/interaction/interactioncontext.go index 9d3f469..3af3188 100644 --- a/objects/interaction/interactioncontext.go +++ b/objects/interaction/interactioncontext.go @@ -3,7 +3,7 @@ package interaction type InteractionContextType int8 const ( - InteractionContextGuild InteractionContextType = 0 - InteractionContextBotDM InteractionContextType = 1 - InteractionContextPrivateChannel InteractionContextType = 2 + InteractionContextGuild InteractionContextType = iota + InteractionContextBotDM + InteractionContextPrivateChannel ) diff --git a/objects/invite/invite.go b/objects/invite/invite.go index 7716639..b51df8e 100644 --- a/objects/invite/invite.go +++ b/objects/invite/invite.go @@ -13,16 +13,16 @@ import ( type InviteType int const ( - InviteTypeGuild InviteType = 0 - InviteTypeGroupDm InviteType = 1 - InviteTypeFriend InviteType = 2 + InviteTypeGuild InviteType = iota + InviteTypeGroupDm + InviteTypeFriend ) type InviteTargetType int const ( - InviteTargetTypeStream InviteTargetType = 1 - InviteTargetTypeEmbeddedApplication InviteTargetType = 2 + InviteTargetTypeStream InviteTargetType = iota + 1 + InviteTargetTypeEmbeddedApplication ) type Invite struct { diff --git a/objects/sku/sku.go b/objects/sku/sku.go index d5ead40..e4e684d 100644 --- a/objects/sku/sku.go +++ b/objects/sku/sku.go @@ -3,10 +3,12 @@ package sku type SKUType int const ( - SKUTypeDurable SKUType = 2 - SKUTypeConsumable SKUType = 3 - SKUTypeSubscription SKUType = 5 - SKUTypeSubscriptionGroup SKUType = 6 + _ SKUType = iota + 1 + SKUTypeDurable + SKUTypeConsumable + _ + SKUTypeSubscription + SKUTypeSubscriptionGroup ) type SKUFlag uint32 From eb0d1379c73d7ffc7b9b07adfa2878d6d5799a2c Mon Sep 17 00:00:00 2001 From: biast12 Date: Fri, 6 Mar 2026 18:49:07 +0100 Subject: [PATCH 68/73] Remove extra spaces in const declarations Normalize spacing in enum/const declarations across several files for consistent formatting. Affected files: objects/guild/scheduledevent/scheduledevent.go (RecurrenceFrequency, RecurrenceWeekday, RecurrenceMonth), objects/guild/sticker/sticker.go (StickerFormatType), objects/interaction/applicationcommandpermissions.go (ApplicationCommandPermissionType), and objects/subscription/subscription.go (SubscriptionStatus). No functional changes. --- objects/guild/scheduledevent/scheduledevent.go | 6 +++--- objects/guild/sticker/sticker.go | 2 +- objects/interaction/applicationcommandpermissions.go | 2 +- objects/subscription/subscription.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/objects/guild/scheduledevent/scheduledevent.go b/objects/guild/scheduledevent/scheduledevent.go index c3d05e6..ae5ed9f 100644 --- a/objects/guild/scheduledevent/scheduledevent.go +++ b/objects/guild/scheduledevent/scheduledevent.go @@ -32,7 +32,7 @@ const ( type RecurrenceFrequency int const ( - RecurrenceFrequencyYearly RecurrenceFrequency = iota + RecurrenceFrequencyYearly RecurrenceFrequency = iota RecurrenceFrequencyMonthly RecurrenceFrequencyWeekly RecurrenceFrequencyDaily @@ -41,7 +41,7 @@ const ( type RecurrenceWeekday int const ( - RecurrenceWeekdayMonday RecurrenceWeekday = iota + RecurrenceWeekdayMonday RecurrenceWeekday = iota RecurrenceWeekdayTuesday RecurrenceWeekdayWednesday RecurrenceWeekdayThursday @@ -53,7 +53,7 @@ const ( type RecurrenceMonth int const ( - RecurrenceMonthJanuary RecurrenceMonth = iota + 1 + RecurrenceMonthJanuary RecurrenceMonth = iota + 1 RecurrenceMonthFebruary RecurrenceMonthMarch RecurrenceMonthApril diff --git a/objects/guild/sticker/sticker.go b/objects/guild/sticker/sticker.go index 47129d2..b1f3957 100644 --- a/objects/guild/sticker/sticker.go +++ b/objects/guild/sticker/sticker.go @@ -12,7 +12,7 @@ const ( type StickerFormatType int const ( - StickerFormatTypePNG StickerFormatType = iota + 1 + StickerFormatTypePNG StickerFormatType = iota + 1 StickerFormatTypeAPNG StickerFormatTypeLottie StickerFormatTypeGIF diff --git a/objects/interaction/applicationcommandpermissions.go b/objects/interaction/applicationcommandpermissions.go index a669b66..14fc5b0 100644 --- a/objects/interaction/applicationcommandpermissions.go +++ b/objects/interaction/applicationcommandpermissions.go @@ -3,7 +3,7 @@ package interaction type ApplicationCommandPermissionType uint8 const ( - ApplicationCommandPermissionTypeRole ApplicationCommandPermissionType = iota + 1 + ApplicationCommandPermissionTypeRole ApplicationCommandPermissionType = iota + 1 ApplicationCommandPermissionTypeUser ApplicationCommandPermissionTypeChannel ) diff --git a/objects/subscription/subscription.go b/objects/subscription/subscription.go index a7923d0..0aa9bb3 100644 --- a/objects/subscription/subscription.go +++ b/objects/subscription/subscription.go @@ -9,7 +9,7 @@ import ( type SubscriptionStatus int const ( - SubscriptionStatusActive SubscriptionStatus = iota + SubscriptionStatusActive SubscriptionStatus = iota SubscriptionStatusEnding SubscriptionStatusInactive ) From 1ab539f7f53aecf5b439cb443a148fd33bf00d60 Mon Sep 17 00:00:00 2001 From: biast12 Date: Fri, 6 Mar 2026 18:51:59 +0100 Subject: [PATCH 69/73] format --- cache/boltcache.go | 8 +- cache/pgcache.go | 8 +- gateway/payloads/events/eventbus.go | 3 +- gateway/payloads/events/guildsoundboard.go | 4 +- gateway/payloads/events/invitecreate.go | 24 +++--- .../payloads/events/voicechanneleffectsend.go | 14 ++-- gateway/payloads/events/voiceserverupdate.go | 4 +- gateway/payloads/heartbeatack.go | 5 +- gateway/payloads/payload.go | 6 +- gateway/state.go | 2 +- gateway/wrappedreader.go | 2 +- objects/application/application.go | 60 +++++++-------- objects/auditlog/changekey.go | 12 +-- objects/channel/attachment.go | 26 +++---- objects/channel/channel.go | 72 +++++++++--------- objects/channel/embed/embed.go | 12 +-- objects/channel/message/message.go | 74 +++++++++---------- objects/channel/message/messageinteraction.go | 18 ++--- objects/channel/message/timestamp.go | 2 +- objects/channel/thread.go | 10 +-- objects/guild/role.go | 4 +- .../component/component_channel_select.go | 4 +- objects/interaction/interaction.go | 30 ++++---- objects/member/member.go | 26 +++---- objects/user/avatar.go | 4 +- objects/user/user.go | 32 ++++---- rest/channel.go | 12 +-- rest/guild.go | 2 +- rest/interaction.go | 22 +++--- rest/scheduledevent.go | 22 +++--- utils/reflectionutils.go | 1 - utils/uintstringslice.go | 1 - 32 files changed, 261 insertions(+), 265 deletions(-) diff --git a/cache/boltcache.go b/cache/boltcache.go index 32d3c76..a307ab0 100644 --- a/cache/boltcache.go +++ b/cache/boltcache.go @@ -737,10 +737,10 @@ func (c *BoltCache) StoreVoiceStates(states []guild.VoiceState) { for _, state := range states { if encoded, err := json.Marshal(state.ToCachedVoiceState()); err == nil { guildId := uint64(0) - if state.GuildId != nil { - guildId = *state.GuildId - } - if err := b.Put(memberToBytes(state.UserId, guildId), encoded); err != nil { + if state.GuildId != nil { + guildId = *state.GuildId + } + if err := b.Put(memberToBytes(state.UserId, guildId), encoded); err != nil { return err } } else { diff --git a/cache/pgcache.go b/cache/pgcache.go index 7539b18..6a25de0 100644 --- a/cache/pgcache.go +++ b/cache/pgcache.go @@ -256,10 +256,10 @@ func (c *PgCache) StoreGuilds(ctx context.Context, guilds []guild.Guild) error { } var chGuildId uint64 - if channel.GuildId != nil { - chGuildId = *channel.GuildId - } - batch.Queue(`INSERT INTO channels("channel_id", "guild_id", "data") VALUES($1, $2, $3) ON CONFLICT("channel_id") DO UPDATE SET "data" = $3;`, channel.Id, chGuildId, string(encoded)) + if channel.GuildId != nil { + chGuildId = *channel.GuildId + } + batch.Queue(`INSERT INTO channels("channel_id", "guild_id", "data") VALUES($1, $2, $3) ON CONFLICT("channel_id") DO UPDATE SET "data" = $3;`, channel.Id, chGuildId, string(encoded)) } } diff --git a/gateway/payloads/events/eventbus.go b/gateway/payloads/events/eventbus.go index 0d106c4..fc9facf 100644 --- a/gateway/payloads/events/eventbus.go +++ b/gateway/payloads/events/eventbus.go @@ -5,8 +5,7 @@ type EventBus struct { } func NewEventBus() *EventBus { - return &EventBus{ - } + return &EventBus{} } func (e *EventBus) RegisterListener(fn interface{}) { diff --git a/gateway/payloads/events/guildsoundboard.go b/gateway/payloads/events/guildsoundboard.go index 9f55e42..fbdfd12 100644 --- a/gateway/payloads/events/guildsoundboard.go +++ b/gateway/payloads/events/guildsoundboard.go @@ -16,11 +16,11 @@ type GuildSoundboardSoundDelete struct { } type GuildSoundboardSoundsUpdate struct { - GuildId uint64 `json:"guild_id,string"` + GuildId uint64 `json:"guild_id,string"` SoundboardSounds []soundboard.SoundboardSound `json:"soundboard_sounds"` } type SoundboardSounds struct { - GuildId uint64 `json:"guild_id,string"` + GuildId uint64 `json:"guild_id,string"` SoundboardSounds []soundboard.SoundboardSound `json:"soundboard_sounds"` } diff --git a/gateway/payloads/events/invitecreate.go b/gateway/payloads/events/invitecreate.go index bf4f747..6757369 100644 --- a/gateway/payloads/events/invitecreate.go +++ b/gateway/payloads/events/invitecreate.go @@ -7,16 +7,16 @@ import ( ) type InviteCreate struct { - ChannelId uint64 `json:"channel_id,string"` - Code string `json:"code"` - CreatedAt time.Time `json:"created_at"` - GuildId *uint64 `json:"guild_id,string"` - Inviter *user.User `json:"inviter"` - MaxAge int `json:"max_age"` - MaxUses int `json:"max_uses"` - TargetType *int `json:"target_type"` - TargetUser *user.User `json:"target_user"` - Temporary bool `json:"temporary"` - Uses int `json:"uses"` - ExpiresAt *time.Time `json:"expires_at"` + ChannelId uint64 `json:"channel_id,string"` + Code string `json:"code"` + CreatedAt time.Time `json:"created_at"` + GuildId *uint64 `json:"guild_id,string"` + Inviter *user.User `json:"inviter"` + MaxAge int `json:"max_age"` + MaxUses int `json:"max_uses"` + TargetType *int `json:"target_type"` + TargetUser *user.User `json:"target_user"` + Temporary bool `json:"temporary"` + Uses int `json:"uses"` + ExpiresAt *time.Time `json:"expires_at"` } diff --git a/gateway/payloads/events/voicechanneleffectsend.go b/gateway/payloads/events/voicechanneleffectsend.go index fd338a7..71d5437 100644 --- a/gateway/payloads/events/voicechanneleffectsend.go +++ b/gateway/payloads/events/voicechanneleffectsend.go @@ -3,12 +3,12 @@ package events import "github.com/TicketsBot-cloud/gdl/objects/guild/emoji" type VoiceChannelEffectSend struct { - ChannelId uint64 `json:"channel_id,string"` - GuildId uint64 `json:"guild_id,string"` - UserId uint64 `json:"user_id,string"` + ChannelId uint64 `json:"channel_id,string"` + GuildId uint64 `json:"guild_id,string"` + UserId uint64 `json:"user_id,string"` Emoji *emoji.Emoji `json:"emoji"` - AnimationType *int `json:"animation_type"` - AnimationId uint `json:"animation_id"` - SoundId *uint64 `json:"sound_id,string"` - SoundVolume *float64 `json:"sound_volume"` + AnimationType *int `json:"animation_type"` + AnimationId uint `json:"animation_id"` + SoundId *uint64 `json:"sound_id,string"` + SoundVolume *float64 `json:"sound_volume"` } diff --git a/gateway/payloads/events/voiceserverupdate.go b/gateway/payloads/events/voiceserverupdate.go index 6a59bcf..88a83ac 100644 --- a/gateway/payloads/events/voiceserverupdate.go +++ b/gateway/payloads/events/voiceserverupdate.go @@ -1,7 +1,7 @@ package events type VoiceServerUpdate struct { - Token string `json:"token"` - GuildId uint64 `json:"guild_id,string"` + Token string `json:"token"` + GuildId uint64 `json:"guild_id,string"` Endpoint *string `json:"endpoint"` } diff --git a/gateway/payloads/heartbeatack.go b/gateway/payloads/heartbeatack.go index 83b1737..c66e141 100644 --- a/gateway/payloads/heartbeatack.go +++ b/gateway/payloads/heartbeatack.go @@ -5,13 +5,14 @@ import ( ) type HeartbeatAck struct { - Opcode int `json:"op"` + Opcode int `json:"op"` SequenceNumber int `json:"d"` } func NewHeartbeackAck(raw []byte) (Hello, error) { var payload Hello - err := json.Unmarshal(raw, &payload); if err != nil { + err := json.Unmarshal(raw, &payload) + if err != nil { return Hello{}, err } diff --git a/gateway/payloads/payload.go b/gateway/payloads/payload.go index 4558ee1..153a53f 100644 --- a/gateway/payloads/payload.go +++ b/gateway/payloads/payload.go @@ -5,10 +5,10 @@ import ( ) type Payload struct { - Opcode int `json:"op"` + Opcode int `json:"op"` Data json.RawMessage `json:"d"` - SequenceNumber *int `json:"s"` - EventName string `json:"t"` + SequenceNumber *int `json:"s"` + EventName string `json:"t"` } func NewPayload(raw []byte) (Payload, error) { diff --git a/gateway/state.go b/gateway/state.go index 6f10c0c..b7ad062 100644 --- a/gateway/state.go +++ b/gateway/state.go @@ -2,7 +2,7 @@ package gateway type State int -const( +const ( CONNECTED State = iota CONNECTING DISCONNECTING diff --git a/gateway/wrappedreader.go b/gateway/wrappedreader.go index 505e652..4acecc5 100644 --- a/gateway/wrappedreader.go +++ b/gateway/wrappedreader.go @@ -12,7 +12,7 @@ type wrappedReader struct { io.ReadCloser sync.RWMutex closeChan chan struct{} - isClosed bool + isClosed bool } func (r *wrappedReader) Close() error { diff --git a/objects/application/application.go b/objects/application/application.go index 71270ba..cf5a9c7 100644 --- a/objects/application/application.go +++ b/objects/application/application.go @@ -6,37 +6,37 @@ import ( ) type Application struct { - Id uint64 `json:"id,string"` - Name string `json:"name"` - Icon *string `json:"icon"` - Description string `json:"description"` - RpcOrigins []string `json:"rpc_origins,omitempty"` - BotPublic bool `json:"bot_public"` - BotRequireCodeGrant bool `json:"bot_require_code_grant"` - Bot *user.User `json:"bot,omitempty"` - TermsOfServiceUrl *string `json:"terms_of_service_url,omitempty"` - PrivacyPolicyUrl *string `json:"privacy_policy_url,omitempty"` - Owner *user.User `json:"owner,omitempty"` - VerifyKey string `json:"verify_key"` - Team *Team `json:"team"` - GuildId *uint64 `json:"guild_id,string,omitempty"` - Guild *guild.Guild `json:"guild,omitempty"` - PrimarySkuId *uint64 `json:"primary_sku_id,string,omitempty"` - Slug *string `json:"slug,omitempty"` - CoverImage *string `json:"cover_image,omitempty"` - Flags *Flag `json:"flags,omitempty"` - ApproximateGuildCount *int `json:"approximate_guild_count,omitempty"` - ApproximateUserInstallCount *int `json:"approximate_user_install_count,omitempty"` - RedirectUris []string `json:"redirect_uris,omitempty"` - InteractionsEndpointUrl *string `json:"interactions_endpoint_url,omitempty"` - RoleConnectionsVerificationUrl *string `json:"role_connections_verification_url,omitempty"` - EventWebhooksUrl *string `json:"event_webhooks_url,omitempty"` - EventWebhooksStatus ApplicationEventWebhookStatus `json:"event_webhooks_status,omitempty"` - EventWebhooksTypes []string `json:"event_webhooks_types,omitempty"` - Tags []string `json:"tags,omitempty"` - InstallParams *InstallParams `json:"install_params,omitempty"` + Id uint64 `json:"id,string"` + Name string `json:"name"` + Icon *string `json:"icon"` + Description string `json:"description"` + RpcOrigins []string `json:"rpc_origins,omitempty"` + BotPublic bool `json:"bot_public"` + BotRequireCodeGrant bool `json:"bot_require_code_grant"` + Bot *user.User `json:"bot,omitempty"` + TermsOfServiceUrl *string `json:"terms_of_service_url,omitempty"` + PrivacyPolicyUrl *string `json:"privacy_policy_url,omitempty"` + Owner *user.User `json:"owner,omitempty"` + VerifyKey string `json:"verify_key"` + Team *Team `json:"team"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + Guild *guild.Guild `json:"guild,omitempty"` + PrimarySkuId *uint64 `json:"primary_sku_id,string,omitempty"` + Slug *string `json:"slug,omitempty"` + CoverImage *string `json:"cover_image,omitempty"` + Flags *Flag `json:"flags,omitempty"` + ApproximateGuildCount *int `json:"approximate_guild_count,omitempty"` + ApproximateUserInstallCount *int `json:"approximate_user_install_count,omitempty"` + RedirectUris []string `json:"redirect_uris,omitempty"` + InteractionsEndpointUrl *string `json:"interactions_endpoint_url,omitempty"` + RoleConnectionsVerificationUrl *string `json:"role_connections_verification_url,omitempty"` + EventWebhooksUrl *string `json:"event_webhooks_url,omitempty"` + EventWebhooksStatus ApplicationEventWebhookStatus `json:"event_webhooks_status,omitempty"` + EventWebhooksTypes []string `json:"event_webhooks_types,omitempty"` + Tags []string `json:"tags,omitempty"` + InstallParams *InstallParams `json:"install_params,omitempty"` IntegrationTypesConfig map[ApplicationIntegrationType]ApplicationIntegrationTypeConfig `json:"integration_types_config,omitempty"` - CustomInstallUrl *string `json:"custom_install_url,omitempty"` + CustomInstallUrl *string `json:"custom_install_url,omitempty"` } type ApplicationEventWebhookStatus int diff --git a/objects/auditlog/changekey.go b/objects/auditlog/changekey.go index a5b8fc7..14e4176 100644 --- a/objects/auditlog/changekey.go +++ b/objects/auditlog/changekey.go @@ -65,12 +65,12 @@ const ( ChangeKeyExpireGracePeriod ChangeKey = "expire_grace_period" // guild - ChangeKeyDiscoverySplashHash ChangeKey = "discovery_splash_hash" - ChangeKeyBanner ChangeKey = "banner_hash" - ChangeKeyRulesChannelId ChangeKey = "rules_channel_id" - ChangeKeyPublicUpdatesChannelId ChangeKey = "public_updates_channel_id" - ChangeKeyPreferredLocale ChangeKey = "preferred_locale" - ChangeKeyPremiumProgressBarEnabled ChangeKey = "premium_progress_bar_enabled" + ChangeKeyDiscoverySplashHash ChangeKey = "discovery_splash_hash" + ChangeKeyBanner ChangeKey = "banner_hash" + ChangeKeyRulesChannelId ChangeKey = "rules_channel_id" + ChangeKeyPublicUpdatesChannelId ChangeKey = "public_updates_channel_id" + ChangeKeyPreferredLocale ChangeKey = "preferred_locale" + ChangeKeyPremiumProgressBarEnabled ChangeKey = "premium_progress_bar_enabled" // channel ChangeKeyDefaultAutoArchiveDuration ChangeKey = "default_auto_archive_duration" diff --git a/objects/channel/attachment.go b/objects/channel/attachment.go index cd1df56..64e18ba 100644 --- a/objects/channel/attachment.go +++ b/objects/channel/attachment.go @@ -1,18 +1,18 @@ package channel type Attachment struct { - Id uint64 `json:"id,string"` - Filename string `json:"filename"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` - ContentType *string `json:"content_type,omitempty"` - Size int `json:"size"` - Url string `json:"url"` - ProxyUrl string `json:"proxy_url"` - Height *int `json:"height,omitempty"` - Width *int `json:"width,omitempty"` - Ephemeral *bool `json:"ephemeral,omitempty"` + Id uint64 `json:"id,string"` + Filename string `json:"filename"` + Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` + ContentType *string `json:"content_type,omitempty"` + Size int `json:"size"` + Url string `json:"url"` + ProxyUrl string `json:"proxy_url"` + Height *int `json:"height,omitempty"` + Width *int `json:"width,omitempty"` + Ephemeral *bool `json:"ephemeral,omitempty"` DurationSecs *float64 `json:"duration_secs,omitempty"` - Waveform *string `json:"waveform,omitempty"` - Flags *int `json:"flags,omitempty"` + Waveform *string `json:"waveform,omitempty"` + Flags *int `json:"flags,omitempty"` } diff --git a/objects/channel/channel.go b/objects/channel/channel.go index e08387e..cf6a428 100644 --- a/objects/channel/channel.go +++ b/objects/channel/channel.go @@ -5,46 +5,46 @@ import ( "time" "github.com/TicketsBot-cloud/gdl/objects" - "github.com/TicketsBot-cloud/gdl/utils" "github.com/TicketsBot-cloud/gdl/objects/user" + "github.com/TicketsBot-cloud/gdl/utils" ) type Channel struct { - Id uint64 `json:"id,string"` - Type ChannelType `json:"type"` - GuildId *uint64 `json:"guild_id,string,omitempty"` - Position *int `json:"position,omitempty"` - PermissionOverwrites []PermissionOverwrite `json:"permission_overwrites,omitempty"` - Name *string `json:"name,omitempty"` - Topic *string `json:"topic,omitempty"` - Nsfw bool `json:"nsfw,omitempty"` - LastMessageId objects.NullableSnowflake `json:"last_message_id"` - Bitrate int `json:"bitrate,omitempty"` - UserLimit int `json:"user_limit,omitempty"` - RateLimitPerUser int `json:"rate_limit_per_user,omitempty"` - Recipients []user.User `json:"recipients,omitempty"` - Icon *string `json:"icon,omitempty"` - OwnerId *uint64 `json:"owner_id,string,omitempty"` - ApplicationId *uint64 `json:"application_id,string,omitempty"` - Managed *bool `json:"managed,omitempty"` - ParentId objects.NullableSnowflake `json:"parent_id,omitempty"` - LastPinTimestamp *time.Time `json:"last_pin_timestamp,omitempty"` - RtcRegion *string `json:"rtc_region,omitempty"` - VideoQualityMode VideoQualityMode `json:"video_quality_mode,omitempty"` - MessageCount int `json:"message_count,omitempty"` - MemberCount int `json:"member_count,omitempty"` - ThreadMetadata *ThreadMetadata `json:"thread_metadata,omitempty"` - Member *ThreadMember `json:"member,omitempty"` - DefaultAutoArchiveDuration *int `json:"default_auto_archive_duration,omitempty"` - Permissions *string `json:"permissions,omitempty"` - Flags *int `json:"flags,omitempty"` - TotalMessageSent *int `json:"total_message_sent,omitempty"` - AvailableTags []ForumTag `json:"available_tags,omitempty"` - AppliedTags utils.Uint64StringSlice `json:"applied_tags,omitempty"` - DefaultReactionEmoji *DefaultReaction `json:"default_reaction_emoji,omitempty"` - DefaultThreadRateLimitPerUser *int `json:"default_thread_rate_limit_per_user,omitempty"` - DefaultSortOrder *int `json:"default_sort_order,omitempty"` - DefaultForumLayout *int `json:"default_forum_layout,omitempty"` + Id uint64 `json:"id,string"` + Type ChannelType `json:"type"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + Position *int `json:"position,omitempty"` + PermissionOverwrites []PermissionOverwrite `json:"permission_overwrites,omitempty"` + Name *string `json:"name,omitempty"` + Topic *string `json:"topic,omitempty"` + Nsfw bool `json:"nsfw,omitempty"` + LastMessageId objects.NullableSnowflake `json:"last_message_id"` + Bitrate int `json:"bitrate,omitempty"` + UserLimit int `json:"user_limit,omitempty"` + RateLimitPerUser int `json:"rate_limit_per_user,omitempty"` + Recipients []user.User `json:"recipients,omitempty"` + Icon *string `json:"icon,omitempty"` + OwnerId *uint64 `json:"owner_id,string,omitempty"` + ApplicationId *uint64 `json:"application_id,string,omitempty"` + Managed *bool `json:"managed,omitempty"` + ParentId objects.NullableSnowflake `json:"parent_id,omitempty"` + LastPinTimestamp *time.Time `json:"last_pin_timestamp,omitempty"` + RtcRegion *string `json:"rtc_region,omitempty"` + VideoQualityMode VideoQualityMode `json:"video_quality_mode,omitempty"` + MessageCount int `json:"message_count,omitempty"` + MemberCount int `json:"member_count,omitempty"` + ThreadMetadata *ThreadMetadata `json:"thread_metadata,omitempty"` + Member *ThreadMember `json:"member,omitempty"` + DefaultAutoArchiveDuration *int `json:"default_auto_archive_duration,omitempty"` + Permissions *string `json:"permissions,omitempty"` + Flags *int `json:"flags,omitempty"` + TotalMessageSent *int `json:"total_message_sent,omitempty"` + AvailableTags []ForumTag `json:"available_tags,omitempty"` + AppliedTags utils.Uint64StringSlice `json:"applied_tags,omitempty"` + DefaultReactionEmoji *DefaultReaction `json:"default_reaction_emoji,omitempty"` + DefaultThreadRateLimitPerUser *int `json:"default_thread_rate_limit_per_user,omitempty"` + DefaultSortOrder *int `json:"default_sort_order,omitempty"` + DefaultForumLayout *int `json:"default_forum_layout,omitempty"` } func (c *Channel) Mention() string { diff --git a/objects/channel/embed/embed.go b/objects/channel/embed/embed.go index 11b4816..c3eb410 100644 --- a/objects/channel/embed/embed.go +++ b/objects/channel/embed/embed.go @@ -3,12 +3,12 @@ package embed import "time" type Embed struct { - Title string `json:"title,omitempty"` - Type *string `json:"type,omitempty"` - Description string `json:"description,omitempty"` - Url string `json:"url,omitempty"` - Timestamp *time.Time `json:"timestamp,omitempty"` - Color int `json:"color,omitempty"` + Title string `json:"title,omitempty"` + Type *string `json:"type,omitempty"` + Description string `json:"description,omitempty"` + Url string `json:"url,omitempty"` + Timestamp *time.Time `json:"timestamp,omitempty"` + Color int `json:"color,omitempty"` Footer *EmbedFooter `json:"footer,omitempty"` Image *EmbedImage `json:"image,omitempty"` Thumbnail *EmbedThumbnail `json:"thumbnail,omitempty"` diff --git a/objects/channel/message/message.go b/objects/channel/message/message.go index 4f549f2..0deabbb 100644 --- a/objects/channel/message/message.go +++ b/objects/channel/message/message.go @@ -15,43 +15,43 @@ import ( ) type Message struct { - Id uint64 `json:"id,string"` - ChannelId uint64 `json:"channel_id,string"` - GuildId *uint64 `json:"guild_id,string,omitempty"` - Author user.User `json:"author"` - Member *member.Member `json:"member,omitempty"` - Content string `json:"content"` - Timestamp time.Time `json:"timestamp"` - EditedTimestamp *time.Time `json:"edited_timestamp,omitempty"` - Tts bool `json:"tts"` - MentionEveryone bool `json:"mention_everyone"` - Mentions []MessageMentionedUser `json:"mentions,omitempty"` // The user objects in the mentions array will only have the partial member field present in MESSAGE_CREATE and MESSAGE_UPDATE events from text-based guild channels - MentionRoles utils.Uint64StringSlice `json:"mention_roles"` - MentionChannels []ChannelMention `json:"mention_channels,omitempty"` // Not all channel mentions in a message will appear in mention_channels. Only textual channels that are visible to everyone in a lurkable guild will ever be included. - Attachments []channel.Attachment `json:"attachments,omitempty"` - Embeds []embed.Embed `json:"embeds,omitempty"` - Reactions []Reaction `json:"reactions,omitempty"` - Nonce interface{} `json:"nonce,omitempty"` - Pinned bool `json:"pinned"` - WebhookId *uint64 `json:"webhook_id,string,omitempty"` - Type MessageType `json:"type"` - Activity *MessageActivity `json:"activity,omitempty"` - Application *MessageApplication `json:"application,omitempty"` - ApplicationId *uint64 `json:"application_id,string,omitempty"` - Flags MessageFlag `json:"flags,omitempty"` - MessageReference *MessageReference `json:"message_reference,omitempty"` - MessageSnapshots []MessageSnapshot `json:"message_snapshots,omitempty"` - ReferencedMessage *Message `json:"referenced_message,omitempty"` - InteractionMetadata *MessageInteractionMetadata `json:"interaction_metadata,omitempty"` - Interaction *MessageInteraction `json:"interaction,omitempty"` // Deprecated: use InteractionMetadata - Thread *channel.Channel `json:"thread,omitempty"` - Components []component.Component `json:"components,omitempty"` - StickerItems []StickerItem `json:"sticker_items,omitempty"` - Stickers []sticker.Sticker `json:"stickers,omitempty"` - Position *int `json:"position,omitempty"` - RoleSubscriptionData *RoleSubscriptionData `json:"role_subscription_data,omitempty"` - Poll *Poll `json:"poll,omitempty"` - Call *MessageCall `json:"call,omitempty"` + Id uint64 `json:"id,string"` + ChannelId uint64 `json:"channel_id,string"` + GuildId *uint64 `json:"guild_id,string,omitempty"` + Author user.User `json:"author"` + Member *member.Member `json:"member,omitempty"` + Content string `json:"content"` + Timestamp time.Time `json:"timestamp"` + EditedTimestamp *time.Time `json:"edited_timestamp,omitempty"` + Tts bool `json:"tts"` + MentionEveryone bool `json:"mention_everyone"` + Mentions []MessageMentionedUser `json:"mentions,omitempty"` // The user objects in the mentions array will only have the partial member field present in MESSAGE_CREATE and MESSAGE_UPDATE events from text-based guild channels + MentionRoles utils.Uint64StringSlice `json:"mention_roles"` + MentionChannels []ChannelMention `json:"mention_channels,omitempty"` // Not all channel mentions in a message will appear in mention_channels. Only textual channels that are visible to everyone in a lurkable guild will ever be included. + Attachments []channel.Attachment `json:"attachments,omitempty"` + Embeds []embed.Embed `json:"embeds,omitempty"` + Reactions []Reaction `json:"reactions,omitempty"` + Nonce interface{} `json:"nonce,omitempty"` + Pinned bool `json:"pinned"` + WebhookId *uint64 `json:"webhook_id,string,omitempty"` + Type MessageType `json:"type"` + Activity *MessageActivity `json:"activity,omitempty"` + Application *MessageApplication `json:"application,omitempty"` + ApplicationId *uint64 `json:"application_id,string,omitempty"` + Flags MessageFlag `json:"flags,omitempty"` + MessageReference *MessageReference `json:"message_reference,omitempty"` + MessageSnapshots []MessageSnapshot `json:"message_snapshots,omitempty"` + ReferencedMessage *Message `json:"referenced_message,omitempty"` + InteractionMetadata *MessageInteractionMetadata `json:"interaction_metadata,omitempty"` + Interaction *MessageInteraction `json:"interaction,omitempty"` // Deprecated: use InteractionMetadata + Thread *channel.Channel `json:"thread,omitempty"` + Components []component.Component `json:"components,omitempty"` + StickerItems []StickerItem `json:"sticker_items,omitempty"` + Stickers []sticker.Sticker `json:"stickers,omitempty"` + Position *int `json:"position,omitempty"` + RoleSubscriptionData *RoleSubscriptionData `json:"role_subscription_data,omitempty"` + Poll *Poll `json:"poll,omitempty"` + Call *MessageCall `json:"call,omitempty"` } var channelMentionRegex = regexp.MustCompile(`<#(\d+)>`) diff --git a/objects/channel/message/messageinteraction.go b/objects/channel/message/messageinteraction.go index 56c5324..7e91152 100644 --- a/objects/channel/message/messageinteraction.go +++ b/objects/channel/message/messageinteraction.go @@ -15,13 +15,13 @@ type MessageInteraction struct { } type MessageInteractionMetadata struct { - Id uint64 `json:"id,string"` - Type int `json:"type"` - User user.User `json:"user"` - AuthorizingIntegrationOwners map[string]string `json:"authorizing_integration_owners"` - OriginalResponseMessageId *uint64 `json:"original_response_message_id,string,omitempty"` - TargetUser *user.User `json:"target_user,omitempty"` - TargetMessageId *uint64 `json:"target_message_id,string,omitempty"` - InteractedMessageId *uint64 `json:"interacted_message_id,string,omitempty"` - TriggeringInteractionMetadata *MessageInteractionMetadata `json:"triggering_interaction_metadata,omitempty"` + Id uint64 `json:"id,string"` + Type int `json:"type"` + User user.User `json:"user"` + AuthorizingIntegrationOwners map[string]string `json:"authorizing_integration_owners"` + OriginalResponseMessageId *uint64 `json:"original_response_message_id,string,omitempty"` + TargetUser *user.User `json:"target_user,omitempty"` + TargetMessageId *uint64 `json:"target_message_id,string,omitempty"` + InteractedMessageId *uint64 `json:"interacted_message_id,string,omitempty"` + TriggeringInteractionMetadata *MessageInteractionMetadata `json:"triggering_interaction_metadata,omitempty"` } diff --git a/objects/channel/message/timestamp.go b/objects/channel/message/timestamp.go index 7aec44d..48c44ad 100644 --- a/objects/channel/message/timestamp.go +++ b/objects/channel/message/timestamp.go @@ -23,4 +23,4 @@ func BuildTimestamp(timestamp time.Time, style TimestampStyle) string { func BuildTimestampFromUnixSecs(timestamp int64, style TimestampStyle) string { return fmt.Sprintf("", timestamp, style) -} \ No newline at end of file +} diff --git a/objects/channel/thread.go b/objects/channel/thread.go index 42d3db9..63b1a39 100644 --- a/objects/channel/thread.go +++ b/objects/channel/thread.go @@ -16,9 +16,9 @@ type ThreadMetadata struct { } type ThreadMember struct { - ThreadId *uint64 `json:"id,string,omitempty"` - UserId *uint64 `json:"user_id,string,omitempty"` - JoinTimestamp time.Time `json:"join_timestamp"` - Flags uint `json:"flags"` - Member *member.Member `json:"member,omitempty"` + ThreadId *uint64 `json:"id,string,omitempty"` + UserId *uint64 `json:"user_id,string,omitempty"` + JoinTimestamp time.Time `json:"join_timestamp"` + Flags uint `json:"flags"` + Member *member.Member `json:"member,omitempty"` } diff --git a/objects/guild/role.go b/objects/guild/role.go index ff4b57f..1c5fc27 100644 --- a/objects/guild/role.go +++ b/objects/guild/role.go @@ -18,8 +18,8 @@ type Role struct { } type RoleTags struct { - BotId *uint64 `json:"bot_id,string,omitempty"` - IntegrationId *uint64 `json:"integration_id,string,omitempty"` + BotId *uint64 `json:"bot_id,string,omitempty"` + IntegrationId *uint64 `json:"integration_id,string,omitempty"` // PremiumSubscriber, AvailableForPurchase, GuildConnections: key present (even as null) = tag applies PremiumSubscriber *bool `json:"premium_subscriber,omitempty"` SubscriptionListingId *uint64 `json:"subscription_listing_id,string,omitempty"` diff --git a/objects/interaction/component/component_channel_select.go b/objects/interaction/component/component_channel_select.go index 9778ea9..27c8602 100644 --- a/objects/interaction/component/component_channel_select.go +++ b/objects/interaction/component/component_channel_select.go @@ -16,8 +16,8 @@ type ChannelSelect struct { MaxValues *int `json:"max_values,omitempty"` Disabled *bool `json:"disabled,omitempty"` Required *bool `json:"required,omitempty"` -} - +} + func (i ChannelSelect) Type() ComponentType { return ComponentChannelSelect } diff --git a/objects/interaction/interaction.go b/objects/interaction/interaction.go index df87d8f..a1ab54b 100644 --- a/objects/interaction/interaction.go +++ b/objects/interaction/interaction.go @@ -19,21 +19,21 @@ type Interaction struct { type InteractionMetadata struct { Interaction - Id uint64 `json:"id,string"` - ApplicationId uint64 `json:"application_id,string"` - GuildId objects.NullableSnowflake `json:"guild_id"` - ChannelId uint64 `json:"channel_id,string"` - Channel channel.PartialChannel `json:"channel"` - Member *member.Member `json:"member"` - User *user.User `json:"user"` - Token string `json:"token"` - AppPermissions uint64 `json:"app_permissions,string"` - Locale *string `json:"locale,omitempty"` - GuildLocale *string `json:"guild_locale,omitempty"` - Entitlements []entitlement.Entitlement `json:"entitlements"` - AuthorizingIntegrationOwners map[string]string `json:"authorizing_integration_owners"` - Context *InteractionContextType `json:"context,omitempty"` - AttachmentSizeLimit int `json:"attachment_size_limit"` + Id uint64 `json:"id,string"` + ApplicationId uint64 `json:"application_id,string"` + GuildId objects.NullableSnowflake `json:"guild_id"` + ChannelId uint64 `json:"channel_id,string"` + Channel channel.PartialChannel `json:"channel"` + Member *member.Member `json:"member"` + User *user.User `json:"user"` + Token string `json:"token"` + AppPermissions uint64 `json:"app_permissions,string"` + Locale *string `json:"locale,omitempty"` + GuildLocale *string `json:"guild_locale,omitempty"` + Entitlements []entitlement.Entitlement `json:"entitlements"` + AuthorizingIntegrationOwners map[string]string `json:"authorizing_integration_owners"` + Context *InteractionContextType `json:"context,omitempty"` + AttachmentSizeLimit int `json:"attachment_size_limit"` } type InteractionType uint8 diff --git a/objects/member/member.go b/objects/member/member.go index a9a363d..382d175 100644 --- a/objects/member/member.go +++ b/objects/member/member.go @@ -8,19 +8,19 @@ import ( ) type Member struct { - User *user.User `json:"user"` - Nick *string `json:"nick"` - Avatar *string `json:"avatar"` - Banner *string `json:"banner"` - Roles utils.Uint64StringSlice `json:"roles"` - JoinedAt *time.Time `json:"joined_at"` - PremiumSince *time.Time `json:"premium_since"` - Deaf bool `json:"deaf"` - Mute bool `json:"mute"` - Flags int `json:"flags"` - Pending *bool `json:"pending,omitempty"` - Permissions uint64 `json:"permissions,string,omitempty"` - CommunicationDisabledUntil *time.Time `json:"communication_disabled_until,omitempty"` + User *user.User `json:"user"` + Nick *string `json:"nick"` + Avatar *string `json:"avatar"` + Banner *string `json:"banner"` + Roles utils.Uint64StringSlice `json:"roles"` + JoinedAt *time.Time `json:"joined_at"` + PremiumSince *time.Time `json:"premium_since"` + Deaf bool `json:"deaf"` + Mute bool `json:"mute"` + Flags int `json:"flags"` + Pending *bool `json:"pending,omitempty"` + Permissions uint64 `json:"permissions,string,omitempty"` + CommunicationDisabledUntil *time.Time `json:"communication_disabled_until,omitempty"` AvatarDecorationData *user.AvatarDecorationData `json:"avatar_decoration_data,omitempty"` } diff --git a/objects/user/avatar.go b/objects/user/avatar.go index 94ad3e8..8d590db 100644 --- a/objects/user/avatar.go +++ b/objects/user/avatar.go @@ -7,7 +7,7 @@ import ( type Avatar struct { Animated bool - data []uint64 + data []uint64 } func (a *Avatar) String() string { @@ -67,5 +67,3 @@ func (a *Avatar) UnmarshalJSON(data []byte) error { return nil } - - diff --git a/objects/user/user.go b/objects/user/user.go index eb759de..25bb6ad 100644 --- a/objects/user/user.go +++ b/objects/user/user.go @@ -9,21 +9,21 @@ import ( type UserFlag int const ( - UserFlagStaff UserFlag = 1 << 0 - UserFlagPartner UserFlag = 1 << 1 - UserFlagHypesquad UserFlag = 1 << 2 - UserFlagBugHunterLevel1 UserFlag = 1 << 3 - UserFlagHypesquadOnlineHouse1 UserFlag = 1 << 6 - UserFlagHypesquadOnlineHouse2 UserFlag = 1 << 7 - UserFlagHypesquadOnlineHouse3 UserFlag = 1 << 8 - UserFlagPremiumEarlySupporter UserFlag = 1 << 9 - UserFlagTeamPseudoUser UserFlag = 1 << 10 - UserFlagBugHunterLevel2 UserFlag = 1 << 14 - UserFlagVerifiedBot UserFlag = 1 << 16 - UserFlagVerifiedDeveloper UserFlag = 1 << 17 - UserFlagCertifiedModerator UserFlag = 1 << 18 - UserFlagBotHttpInteractions UserFlag = 1 << 19 - UserFlagActiveDeveloper UserFlag = 1 << 22 + UserFlagStaff UserFlag = 1 << 0 + UserFlagPartner UserFlag = 1 << 1 + UserFlagHypesquad UserFlag = 1 << 2 + UserFlagBugHunterLevel1 UserFlag = 1 << 3 + UserFlagHypesquadOnlineHouse1 UserFlag = 1 << 6 + UserFlagHypesquadOnlineHouse2 UserFlag = 1 << 7 + UserFlagHypesquadOnlineHouse3 UserFlag = 1 << 8 + UserFlagPremiumEarlySupporter UserFlag = 1 << 9 + UserFlagTeamPseudoUser UserFlag = 1 << 10 + UserFlagBugHunterLevel2 UserFlag = 1 << 14 + UserFlagVerifiedBot UserFlag = 1 << 16 + UserFlagVerifiedDeveloper UserFlag = 1 << 17 + UserFlagCertifiedModerator UserFlag = 1 << 18 + UserFlagBotHttpInteractions UserFlag = 1 << 19 + UserFlagActiveDeveloper UserFlag = 1 << 22 ) type PremiumType int @@ -76,7 +76,7 @@ type User struct { PremiumType *PremiumType `json:"premium_type,omitempty"` PublicFlags *UserFlag `json:"public_flags,omitempty"` AvatarDecorationData *AvatarDecorationData `json:"avatar_decoration_data,omitempty"` - Collectibles *UserCollectibles `json:"collectibles,omitempty"` + Collectibles *UserCollectibles `json:"collectibles,omitempty"` PrimaryGuild *UserPrimaryGuild `json:"primary_guild,omitempty"` } diff --git a/rest/channel.go b/rest/channel.go index 931c5d2..e27fdcb 100644 --- a/rest/channel.go +++ b/rest/channel.go @@ -328,12 +328,12 @@ func DeleteAllReactionsEmoji(ctx context.Context, token string, rateLimiter *rat } type EditMessageData struct { - Content string `json:"content,omitempty"` - Embeds []*embed.Embed `json:"embeds,omitempty"` - Flags uint `json:"flags,omitempty"` - AllowedMentions *message.AllowedMention `json:"allowed_mentions,omitempty"` - Components []component.Component `json:"components,omitempty"` - Attachments []request.Attachment `json:"attachments,omitempty"` + Content string `json:"content,omitempty"` + Embeds []*embed.Embed `json:"embeds,omitempty"` + Flags uint `json:"flags,omitempty"` + AllowedMentions *message.AllowedMention `json:"allowed_mentions,omitempty"` + Components []component.Component `json:"components,omitempty"` + Attachments []request.Attachment `json:"attachments,omitempty"` } func (d EditMessageData) GetAttachments() []request.Attachment { diff --git a/rest/guild.go b/rest/guild.go index 53fd292..737b4f6 100644 --- a/rest/guild.go +++ b/rest/guild.go @@ -96,7 +96,7 @@ type ModifyGuildData struct { Description *string `json:"description,omitempty"` PremiumProgressBarEnabled *bool `json:"premium_progress_bar_enabled,omitempty"` SafetyAlertsChannelId *uint64 `json:"safety_alerts_channel_id,string,omitempty"` -} +} func ModifyGuild(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data ModifyGuildData) (guild.Guild, error) { endpoint := request.Endpoint{ diff --git a/rest/interaction.go b/rest/interaction.go index e2d5734..b977ca9 100644 --- a/rest/interaction.go +++ b/rest/interaction.go @@ -38,17 +38,17 @@ func GetGlobalCommand(ctx context.Context, token string, rateLimiter *ratelimit. } type CreateCommandData struct { - Id uint64 `json:"id,string,omitempty"` // Use in bulk overwrite to update an existing command by ID - Name string `json:"name"` - NameLocalizations map[string]string `json:"name_localizations,omitempty"` - Description string `json:"description,omitempty"` - DescriptionLocalizations map[string]string `json:"description_localizations,omitempty"` - Options []interaction.ApplicationCommandOption `json:"options,omitempty"` - DefaultMemberPermissions *string `json:"default_member_permissions,omitempty"` - IntegrationTypes []application.ApplicationIntegrationType `json:"integration_types,omitempty"` - Contexts []interaction.InteractionContextType `json:"contexts,omitempty"` - Type interaction.ApplicationCommandType `json:"type,omitempty"` - Nsfw *bool `json:"nsfw,omitempty"` + Id uint64 `json:"id,string,omitempty"` // Use in bulk overwrite to update an existing command by ID + Name string `json:"name"` + NameLocalizations map[string]string `json:"name_localizations,omitempty"` + Description string `json:"description,omitempty"` + DescriptionLocalizations map[string]string `json:"description_localizations,omitempty"` + Options []interaction.ApplicationCommandOption `json:"options,omitempty"` + DefaultMemberPermissions *string `json:"default_member_permissions,omitempty"` + IntegrationTypes []application.ApplicationIntegrationType `json:"integration_types,omitempty"` + Contexts []interaction.InteractionContextType `json:"contexts,omitempty"` + Type interaction.ApplicationCommandType `json:"type,omitempty"` + Nsfw *bool `json:"nsfw,omitempty"` Handler *interaction.ApplicationCommandHandlerType `json:"handler,omitempty"` } diff --git a/rest/scheduledevent.go b/rest/scheduledevent.go index e12e047..baf3c8d 100644 --- a/rest/scheduledevent.go +++ b/rest/scheduledevent.go @@ -28,17 +28,17 @@ type CreateGuildScheduledEventData struct { } type ModifyGuildScheduledEventData struct { - ChannelId *uint64 `json:"channel_id,string,omitempty"` - EntityMetadata *scheduledevent.EntityMetadata `json:"entity_metadata,omitempty"` - Name *string `json:"name,omitempty"` - PrivacyLevel *scheduledevent.PrivacyLevel `json:"privacy_level,omitempty"` - ScheduledStartTime *time.Time `json:"scheduled_start_time,omitempty"` - ScheduledEndTime *time.Time `json:"scheduled_end_time,omitempty"` - Description *string `json:"description,omitempty"` - EntityType *scheduledevent.EntityType `json:"entity_type,omitempty"` - Status *scheduledevent.Status `json:"status,omitempty"` - Image *string `json:"image,omitempty"` - RecurrenceRule *scheduledevent.RecurrenceRule `json:"recurrence_rule,omitempty"` + ChannelId *uint64 `json:"channel_id,string,omitempty"` + EntityMetadata *scheduledevent.EntityMetadata `json:"entity_metadata,omitempty"` + Name *string `json:"name,omitempty"` + PrivacyLevel *scheduledevent.PrivacyLevel `json:"privacy_level,omitempty"` + ScheduledStartTime *time.Time `json:"scheduled_start_time,omitempty"` + ScheduledEndTime *time.Time `json:"scheduled_end_time,omitempty"` + Description *string `json:"description,omitempty"` + EntityType *scheduledevent.EntityType `json:"entity_type,omitempty"` + Status *scheduledevent.Status `json:"status,omitempty"` + Image *string `json:"image,omitempty"` + RecurrenceRule *scheduledevent.RecurrenceRule `json:"recurrence_rule,omitempty"` } type GetGuildScheduledEventUsersData struct { diff --git a/utils/reflectionutils.go b/utils/reflectionutils.go index db8a8da..00521d5 100644 --- a/utils/reflectionutils.go +++ b/utils/reflectionutils.go @@ -33,4 +33,3 @@ func IsZero(v reflect.Value) bool { return result } - diff --git a/utils/uintstringslice.go b/utils/uintstringslice.go index 1da3ab0..a4f36b0 100644 --- a/utils/uintstringslice.go +++ b/utils/uintstringslice.go @@ -43,4 +43,3 @@ func (slice *Uint64StringSlice) UnmarshalJSON(b []byte) error { } return nil } - From da40dcc032408eb412466badb9951871ee556168 Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 27 Apr 2026 14:36:14 +0200 Subject: [PATCH 70/73] Add guild message search and voice/channel updates Introduce SearchGuildMessages REST endpoint and Shard wrapper, including request encoding, response structs and new rate-limit route. Add new gateway event types (CHANNEL_INFO, VOICE_CHANNEL_START_TIME_UPDATE, VOICE_CHANNEL_STATUS_UPDATE) with payload structs and register them in the event registry. Extend objects: add audit log status field and new voice-channel audit events; extend Attachment with flags, placeholders, clip metadata and timestamps; add Message fields (Resolved, SharedClientTheme); add Role.Colors type; add Collectibles to Member and GuildMember payloads; and adjust a small user flags reformatting. Small REST wrapper and route constant updates included. --- gateway/payloads/events/channelinfo.go | 12 ++ gateway/payloads/events/eventtype.go | 9 +- gateway/payloads/events/guildmemberupdate.go | 1 + gateway/payloads/events/registry.go | 12 +- .../events/voicechannelstarttimeupdate.go | 7 + .../events/voicechannelstatusupdate.go | 7 + gateway/restwrapper.go | 4 + objects/auditlog/auditentryinfo.go | 1 + objects/auditlog/auditlogevent.go | 8 +- objects/channel/attachment.go | 48 +++++-- objects/channel/message/message.go | 20 +++ objects/guild/role.go | 31 ++-- objects/member/member.go | 1 + objects/user/user.go | 1 - rest/guild.go | 134 ++++++++++++++++++ rest/ratelimit/routes.go | 3 + 16 files changed, 265 insertions(+), 34 deletions(-) create mode 100644 gateway/payloads/events/channelinfo.go create mode 100644 gateway/payloads/events/voicechannelstarttimeupdate.go create mode 100644 gateway/payloads/events/voicechannelstatusupdate.go diff --git a/gateway/payloads/events/channelinfo.go b/gateway/payloads/events/channelinfo.go new file mode 100644 index 0000000..b1eba26 --- /dev/null +++ b/gateway/payloads/events/channelinfo.go @@ -0,0 +1,12 @@ +package events + +type ChannelInfoChannel struct { + Id uint64 `json:"id,string"` + Status *string `json:"status,omitempty"` + VoiceStartTime *int64 `json:"voice_start_time,omitempty"` +} + +type ChannelInfo struct { + GuildId uint64 `json:"guild_id,string"` + Channels []ChannelInfoChannel `json:"channels"` +} diff --git a/gateway/payloads/events/eventtype.go b/gateway/payloads/events/eventtype.go index 7a40be7..eb0dbca 100644 --- a/gateway/payloads/events/eventtype.go +++ b/gateway/payloads/events/eventtype.go @@ -18,6 +18,7 @@ const ( CHANNEL_CREATE EventType = "CHANNEL_CREATE" CHANNEL_UPDATE EventType = "CHANNEL_UPDATE" CHANNEL_DELETE EventType = "CHANNEL_DELETE" + CHANNEL_INFO EventType = "CHANNEL_INFO" CHANNEL_PINS_UPDATE EventType = "CHANNEL_PINS_UPDATE" THREAD_CREATE EventType = "THREAD_CREATE" @@ -93,9 +94,11 @@ const ( USER_UPDATE EventType = "USER_UPDATE" - VOICE_CHANNEL_EFFECT_SEND EventType = "VOICE_CHANNEL_EFFECT_SEND" - VOICE_STATE_UPDATE EventType = "VOICE_STATE_UPDATE" - VOICE_SERVER_UPDATE EventType = "VOICE_SERVER_UPDATE" + VOICE_CHANNEL_EFFECT_SEND EventType = "VOICE_CHANNEL_EFFECT_SEND" + VOICE_CHANNEL_START_TIME_UPDATE EventType = "VOICE_CHANNEL_START_TIME_UPDATE" + VOICE_CHANNEL_STATUS_UPDATE EventType = "VOICE_CHANNEL_STATUS_UPDATE" + VOICE_STATE_UPDATE EventType = "VOICE_STATE_UPDATE" + VOICE_SERVER_UPDATE EventType = "VOICE_SERVER_UPDATE" WEBHOOKS_UPDATE EventType = "WEBHOOKS_UPDATE" ) diff --git a/gateway/payloads/events/guildmemberupdate.go b/gateway/payloads/events/guildmemberupdate.go index c53bb20..445da47 100644 --- a/gateway/payloads/events/guildmemberupdate.go +++ b/gateway/payloads/events/guildmemberupdate.go @@ -20,4 +20,5 @@ type GuildMemberUpdate struct { Mute *bool `json:"mute"` Pending *bool `json:"pending"` CommunicationDisabledUntil *time.Time `json:"communication_disabled_until"` + Collectibles *user.UserCollectibles `json:"collectibles,omitempty"` } diff --git a/gateway/payloads/events/registry.go b/gateway/payloads/events/registry.go index 22c729a..5f592a3 100644 --- a/gateway/payloads/events/registry.go +++ b/gateway/payloads/events/registry.go @@ -15,6 +15,7 @@ type Event interface { ChannelCreate | ChannelUpdate | ChannelDelete | + ChannelInfo | ChannelPinsUpdate | ThreadCreate | ThreadUpdate | @@ -76,6 +77,8 @@ type Event interface { TypingStart | UserUpdate | VoiceChannelEffectSend | + VoiceChannelStartTimeUpdate | + VoiceChannelStatusUpdate | VoiceServerUpdate | VoiceStateUpdate | WebhooksUpdate @@ -97,6 +100,7 @@ var EventTypes = map[EventType]reflect.Type{ CHANNEL_CREATE: reflect.TypeOf(ChannelCreate{}), CHANNEL_UPDATE: reflect.TypeOf(ChannelUpdate{}), CHANNEL_DELETE: reflect.TypeOf(ChannelDelete{}), + CHANNEL_INFO: reflect.TypeOf(ChannelInfo{}), CHANNEL_PINS_UPDATE: reflect.TypeOf(ChannelPinsUpdate{}), THREAD_CREATE: reflect.TypeOf(ThreadCreate{}), @@ -169,9 +173,11 @@ var EventTypes = map[EventType]reflect.Type{ USER_UPDATE: reflect.TypeOf(UserUpdate{}), - VOICE_CHANNEL_EFFECT_SEND: reflect.TypeOf(VoiceChannelEffectSend{}), - VOICE_STATE_UPDATE: reflect.TypeOf(VoiceStateUpdate{}), - VOICE_SERVER_UPDATE: reflect.TypeOf(VoiceServerUpdate{}), + VOICE_CHANNEL_EFFECT_SEND: reflect.TypeOf(VoiceChannelEffectSend{}), + VOICE_CHANNEL_START_TIME_UPDATE: reflect.TypeOf(VoiceChannelStartTimeUpdate{}), + VOICE_CHANNEL_STATUS_UPDATE: reflect.TypeOf(VoiceChannelStatusUpdate{}), + VOICE_STATE_UPDATE: reflect.TypeOf(VoiceStateUpdate{}), + VOICE_SERVER_UPDATE: reflect.TypeOf(VoiceServerUpdate{}), WEBHOOKS_UPDATE: reflect.TypeOf(WebhooksUpdate{}), } diff --git a/gateway/payloads/events/voicechannelstarttimeupdate.go b/gateway/payloads/events/voicechannelstarttimeupdate.go new file mode 100644 index 0000000..d66ba1c --- /dev/null +++ b/gateway/payloads/events/voicechannelstarttimeupdate.go @@ -0,0 +1,7 @@ +package events + +type VoiceChannelStartTimeUpdate struct { + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + VoiceStartTime *int64 `json:"voice_start_time"` +} diff --git a/gateway/payloads/events/voicechannelstatusupdate.go b/gateway/payloads/events/voicechannelstatusupdate.go new file mode 100644 index 0000000..579f8ef --- /dev/null +++ b/gateway/payloads/events/voicechannelstatusupdate.go @@ -0,0 +1,7 @@ +package events + +type VoiceChannelStatusUpdate struct { + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + Status *string `json:"status"` +} diff --git a/gateway/restwrapper.go b/gateway/restwrapper.go index 43d8cef..97f4440 100644 --- a/gateway/restwrapper.go +++ b/gateway/restwrapper.go @@ -725,3 +725,7 @@ func (s *Shard) EditCommandPermissions(ctx context.Context, applicationId, guild func (s *Shard) EditBulkCommandPermissions(ctx context.Context, applicationId, guildId uint64, data []rest.CommandWithPermissionsData) ([]rest.CommandWithPermissionsData, error) { return rest.EditBulkCommandPermissions(ctx, s.Token, s.ShardManager.RateLimiter, applicationId, guildId, data) } + +func (s *Shard) SearchGuildMessages(ctx context.Context, guildId uint64, data rest.SearchGuildMessagesData) (rest.SearchGuildMessagesResponse, error) { + return rest.SearchGuildMessages(ctx, s.Token, s.ShardManager.RateLimiter, guildId, data) +} diff --git a/objects/auditlog/auditentryinfo.go b/objects/auditlog/auditentryinfo.go index a8ab7e8..66c557e 100644 --- a/objects/auditlog/auditentryinfo.go +++ b/objects/auditlog/auditentryinfo.go @@ -14,4 +14,5 @@ type AuditEntryInfo struct { MessageId *uint64 `json:"message_id,string,omitempty"` // MESSAGE_PIN & MESSAGE_UNPIN RoleName string `json:"role_name,omitempty"` // CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE Type EntityType `json:"type,omitempty"` // CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE + Status string `json:"status,omitempty"` // VOICE_CHANNEL_STATUS_UPDATE } diff --git a/objects/auditlog/auditlogevent.go b/objects/auditlog/auditlogevent.go index 37b1a98..2c0de74 100644 --- a/objects/auditlog/auditlogevent.go +++ b/objects/auditlog/auditlogevent.go @@ -101,7 +101,8 @@ const ( AuditLogEventAutoModerationRuleDelete AuditLogEventAutoModerationBlockMessage AuditLogEventAutoModerationFlagToChannel - AuditLogEventAutoModerationUserCommunicationDis + AuditLogEventAutoModerationUserCommunicationDisabled + AuditLogEventAutoModerationQuarantineUser ) const ( @@ -121,3 +122,8 @@ const ( AuditLogEventHomeSettingsCreate AuditLogEvent = iota + 190 AuditLogEventHomeSettingsUpdate ) + +const ( + AuditLogEventVoiceChannelStatusUpdate AuditLogEvent = iota + 192 + AuditLogEventVoiceChannelStatusDelete +) diff --git a/objects/channel/attachment.go b/objects/channel/attachment.go index 64e18ba..c2ea0e3 100644 --- a/objects/channel/attachment.go +++ b/objects/channel/attachment.go @@ -1,18 +1,38 @@ package channel +import ( + "time" + + "github.com/TicketsBot-cloud/gdl/objects/user" +) + +type AttachmentFlag int + +const ( + AttachmentFlagIsClip AttachmentFlag = 1 << 0 + AttachmentFlagIsThumbnail AttachmentFlag = 1 << 1 + AttachmentFlagIsRemix AttachmentFlag = 1 << 2 + AttachmentFlagIsSpoiler AttachmentFlag = 1 << 3 + AttachmentFlagIsAnimated AttachmentFlag = 1 << 5 +) + type Attachment struct { - Id uint64 `json:"id,string"` - Filename string `json:"filename"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` - ContentType *string `json:"content_type,omitempty"` - Size int `json:"size"` - Url string `json:"url"` - ProxyUrl string `json:"proxy_url"` - Height *int `json:"height,omitempty"` - Width *int `json:"width,omitempty"` - Ephemeral *bool `json:"ephemeral,omitempty"` - DurationSecs *float64 `json:"duration_secs,omitempty"` - Waveform *string `json:"waveform,omitempty"` - Flags *int `json:"flags,omitempty"` + Id uint64 `json:"id,string"` + Filename string `json:"filename"` + Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` + ContentType *string `json:"content_type,omitempty"` + Size int `json:"size"` + Url string `json:"url"` + ProxyUrl string `json:"proxy_url"` + Height *int `json:"height,omitempty"` + Width *int `json:"width,omitempty"` + Placeholder *string `json:"placeholder,omitempty"` + PlaceholderVersion *int `json:"placeholder_version,omitempty"` + Ephemeral *bool `json:"ephemeral,omitempty"` + DurationSecs *float64 `json:"duration_secs,omitempty"` + Waveform *string `json:"waveform,omitempty"` + Flags *AttachmentFlag `json:"flags,omitempty"` + ClipParticipants []user.User `json:"clip_participants,omitempty"` + ClipCreatedAt *time.Time `json:"clip_created_at,omitempty"` } diff --git a/objects/channel/message/message.go b/objects/channel/message/message.go index 0deabbb..8977d33 100644 --- a/objects/channel/message/message.go +++ b/objects/channel/message/message.go @@ -1,6 +1,7 @@ package message import ( + "encoding/json" "regexp" "strconv" "time" @@ -14,6 +15,23 @@ import ( "github.com/TicketsBot-cloud/gdl/utils" ) +type BaseThemeType int + +const ( + BaseThemeUnset BaseThemeType = 0 + BaseThemeDark BaseThemeType = 1 + BaseThemeLight BaseThemeType = 2 + BaseThemeDarker BaseThemeType = 3 + BaseThemeMidnight BaseThemeType = 4 +) + +type SharedClientTheme struct { + Colors []string `json:"colors"` + GradientAngle int `json:"gradient_angle"` + BaseMix int `json:"base_mix"` + BaseTheme *BaseThemeType `json:"base_theme,omitempty"` +} + type Message struct { Id uint64 `json:"id,string"` ChannelId uint64 `json:"channel_id,string"` @@ -52,6 +70,8 @@ type Message struct { RoleSubscriptionData *RoleSubscriptionData `json:"role_subscription_data,omitempty"` Poll *Poll `json:"poll,omitempty"` Call *MessageCall `json:"call,omitempty"` + Resolved json.RawMessage `json:"resolved,omitempty"` + SharedClientTheme *SharedClientTheme `json:"shared_client_theme,omitempty"` } var channelMentionRegex = regexp.MustCompile(`<#(\d+)>`) diff --git a/objects/guild/role.go b/objects/guild/role.go index 1c5fc27..108784b 100644 --- a/objects/guild/role.go +++ b/objects/guild/role.go @@ -2,19 +2,26 @@ package guild import "fmt" +type RoleColors struct { + PrimaryColor int `json:"primary_color"` + SecondaryColor *int `json:"secondary_color,omitempty"` + TertiaryColor *int `json:"tertiary_color,omitempty"` +} + type Role struct { - Id uint64 `json:"id,string"` - Name string `json:"name"` - Color int `json:"color"` - Hoist bool `json:"hoist"` - Icon *string `json:"icon"` - UnicodeEmoji *string `json:"unicode_emoji"` - Position int `json:"position"` - Permissions uint64 `json:"permissions,string"` - Managed bool `json:"managed"` - Mentionable bool `json:"mentionable"` - Flags int `json:"flags"` - Tags RoleTags `json:"tags"` + Id uint64 `json:"id,string"` + Name string `json:"name"` + Color int `json:"color"` + Colors RoleColors `json:"colors"` + Hoist bool `json:"hoist"` + Icon *string `json:"icon"` + UnicodeEmoji *string `json:"unicode_emoji"` + Position int `json:"position"` + Permissions uint64 `json:"permissions,string"` + Managed bool `json:"managed"` + Mentionable bool `json:"mentionable"` + Flags int `json:"flags"` + Tags RoleTags `json:"tags"` } type RoleTags struct { diff --git a/objects/member/member.go b/objects/member/member.go index 382d175..3460385 100644 --- a/objects/member/member.go +++ b/objects/member/member.go @@ -22,6 +22,7 @@ type Member struct { Permissions uint64 `json:"permissions,string,omitempty"` CommunicationDisabledUntil *time.Time `json:"communication_disabled_until,omitempty"` AvatarDecorationData *user.AvatarDecorationData `json:"avatar_decoration_data,omitempty"` + Collectibles *user.UserCollectibles `json:"collectibles,omitempty"` } func (m *Member) HasRole(roleId uint64) bool { diff --git a/objects/user/user.go b/objects/user/user.go index 25bb6ad..aa466ff 100644 --- a/objects/user/user.go +++ b/objects/user/user.go @@ -23,7 +23,6 @@ const ( UserFlagVerifiedDeveloper UserFlag = 1 << 17 UserFlagCertifiedModerator UserFlag = 1 << 18 UserFlagBotHttpInteractions UserFlag = 1 << 19 - UserFlagActiveDeveloper UserFlag = 1 << 22 ) type PremiumType int diff --git a/rest/guild.go b/rest/guild.go index 737b4f6..938ffaf 100644 --- a/rest/guild.go +++ b/rest/guild.go @@ -8,6 +8,7 @@ import ( "time" "github.com/TicketsBot-cloud/gdl/objects/channel" + "github.com/TicketsBot-cloud/gdl/objects/channel/message" "github.com/TicketsBot-cloud/gdl/objects/guild" "github.com/TicketsBot-cloud/gdl/objects/integration" "github.com/TicketsBot-cloud/gdl/objects/invite" @@ -777,3 +778,136 @@ func ModifyGuildWelcomeScreen(ctx context.Context, token string, rateLimiter *ra return screen, nil } + +// All fields are optional +type SearchGuildMessagesData struct { + Limit int // 1-25, default 25 + Offset int // max 9975 + MaxId uint64 // Get messages before this message ID + MinId uint64 // Get messages after this message ID + Slop int // Max words to skip between tokens (max 100, default 2) + Content string // Filter by content (max 1024 chars) + ChannelIds []uint64 // Filter by channels (max 500) + AuthorTypes []string // Filter by author type: "user", "bot", "webhook" (prefix with "-" to negate) + AuthorIds []uint64 // Filter by authors (max 100) + Mentions []uint64 // Filter by mentioned users (max 100) + MentionsRoleIds []uint64 // Filter by mentioned roles (max 100) + MentionEveryone *bool // Filter by @everyone mention + RepliedToUserIds []uint64 // Filter by replied-to users (max 100) + RepliedToMessageIds []uint64 // Filter by replied-to messages (max 100) + Pinned *bool // Filter by pinned status + Has []string // Filter by content type: "image", "sound", "video", "file", "sticker", "embed", "link", "poll", "snapshot" + EmbedTypes []string // Filter by embed type: "image", "video", "gif", "sound", "article" + EmbedProviders []string // Filter by embed provider (max 100) + LinkHostnames []string // Filter by link hostname (max 100) + AttachmentFilenames []string // Filter by attachment filename (max 100) + AttachmentExtensions []string // Filter by attachment extension (max 100) + SortBy string // "timestamp" or "relevance" + SortOrder string // "asc" or "desc" + IncludeNsfw *bool // Whether to include age-restricted channels (default false) +} + +func (d *SearchGuildMessagesData) Encode() string { + q := url.Values{} + + if d.Limit != 0 { + q.Set("limit", strconv.Itoa(d.Limit)) + } + if d.Offset != 0 { + q.Set("offset", strconv.Itoa(d.Offset)) + } + if d.MaxId != 0 { + q.Set("max_id", strconv.FormatUint(d.MaxId, 10)) + } + if d.MinId != 0 { + q.Set("min_id", strconv.FormatUint(d.MinId, 10)) + } + if d.Slop != 0 { + q.Set("slop", strconv.Itoa(d.Slop)) + } + if d.Content != "" { + q.Set("content", d.Content) + } + for _, id := range d.ChannelIds { + q.Add("channel_id", strconv.FormatUint(id, 10)) + } + for _, t := range d.AuthorTypes { + q.Add("author_type", t) + } + for _, id := range d.AuthorIds { + q.Add("author_id", strconv.FormatUint(id, 10)) + } + for _, id := range d.Mentions { + q.Add("mentions", strconv.FormatUint(id, 10)) + } + for _, id := range d.MentionsRoleIds { + q.Add("mentions_role_id", strconv.FormatUint(id, 10)) + } + if d.MentionEveryone != nil { + q.Set("mention_everyone", strconv.FormatBool(*d.MentionEveryone)) + } + for _, id := range d.RepliedToUserIds { + q.Add("replied_to_user_id", strconv.FormatUint(id, 10)) + } + for _, id := range d.RepliedToMessageIds { + q.Add("replied_to_message_id", strconv.FormatUint(id, 10)) + } + if d.Pinned != nil { + q.Set("pinned", strconv.FormatBool(*d.Pinned)) + } + for _, h := range d.Has { + q.Add("has", h) + } + for _, t := range d.EmbedTypes { + q.Add("embed_type", t) + } + for _, p := range d.EmbedProviders { + q.Add("embed_provider", p) + } + for _, h := range d.LinkHostnames { + q.Add("link_hostname", h) + } + for _, f := range d.AttachmentFilenames { + q.Add("attachment_filename", f) + } + for _, e := range d.AttachmentExtensions { + q.Add("attachment_extension", e) + } + if d.SortBy != "" { + q.Set("sort_by", d.SortBy) + } + if d.SortOrder != "" { + q.Set("sort_order", d.SortOrder) + } + if d.IncludeNsfw != nil { + q.Set("include_nsfw", strconv.FormatBool(*d.IncludeNsfw)) + } + + return q.Encode() +} + +type SearchGuildMessagesResponse struct { + DoingDeepHistoricalIndex bool `json:"doing_deep_historical_index"` + DocumentsIndexed *int `json:"documents_indexed,omitempty"` + TotalResults int `json:"total_results"` + Messages [][]message.Message `json:"messages"` + Threads []channel.Channel `json:"threads,omitempty"` + Members []channel.ThreadMember `json:"members,omitempty"` +} + +func SearchGuildMessages(ctx context.Context, token string, rateLimiter *ratelimit.Ratelimiter, guildId uint64, data SearchGuildMessagesData) (SearchGuildMessagesResponse, error) { + endpoint := request.Endpoint{ + RequestType: request.GET, + ContentType: request.Nil, + Endpoint: fmt.Sprintf("/guilds/%d/messages/search?%s", guildId, data.Encode()), + Route: ratelimit.NewGuildRoute(ratelimit.RouteSearchGuildMessages, guildId), + RateLimiter: rateLimiter, + } + + var res SearchGuildMessagesResponse + if err, _ := endpoint.Request(ctx, token, nil, &res); err != nil { + return SearchGuildMessagesResponse{}, err + } + + return res, nil +} diff --git a/rest/ratelimit/routes.go b/rest/ratelimit/routes.go index 97179fc..dc747a7 100644 --- a/rest/ratelimit/routes.go +++ b/rest/ratelimit/routes.go @@ -300,4 +300,7 @@ const ( // Guild Welcome Screen RouteGetGuildWelcomeScreen RouteModifyGuildWelcomeScreen + + // Guild Message Search + RouteSearchGuildMessages ) From f87758f758e13f00ab5fc6177dcc916a88b36e3a Mon Sep 17 00:00:00 2001 From: biast12 Date: Mon, 27 Apr 2026 20:53:56 +0200 Subject: [PATCH 71/73] Format Go structs and constants for alignment Reformat code for consistent spacing/alignment across several files: normalize spacing in EventType constants, tidy struct field spacing in VoiceChannelStartTimeUpdate, and align field types in SearchGuildMessagesResponse. Purely formatting changes; no logic or behavior was modified. Files updated: gateway/payloads/events/eventtype.go, gateway/payloads/events/voicechannelstarttimeupdate.go, rest/guild.go. --- gateway/payloads/events/eventtype.go | 10 +++++----- gateway/payloads/events/voicechannelstarttimeupdate.go | 6 +++--- rest/guild.go | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/gateway/payloads/events/eventtype.go b/gateway/payloads/events/eventtype.go index eb0dbca..534b979 100644 --- a/gateway/payloads/events/eventtype.go +++ b/gateway/payloads/events/eventtype.go @@ -94,11 +94,11 @@ const ( USER_UPDATE EventType = "USER_UPDATE" - VOICE_CHANNEL_EFFECT_SEND EventType = "VOICE_CHANNEL_EFFECT_SEND" - VOICE_CHANNEL_START_TIME_UPDATE EventType = "VOICE_CHANNEL_START_TIME_UPDATE" - VOICE_CHANNEL_STATUS_UPDATE EventType = "VOICE_CHANNEL_STATUS_UPDATE" - VOICE_STATE_UPDATE EventType = "VOICE_STATE_UPDATE" - VOICE_SERVER_UPDATE EventType = "VOICE_SERVER_UPDATE" + VOICE_CHANNEL_EFFECT_SEND EventType = "VOICE_CHANNEL_EFFECT_SEND" + VOICE_CHANNEL_START_TIME_UPDATE EventType = "VOICE_CHANNEL_START_TIME_UPDATE" + VOICE_CHANNEL_STATUS_UPDATE EventType = "VOICE_CHANNEL_STATUS_UPDATE" + VOICE_STATE_UPDATE EventType = "VOICE_STATE_UPDATE" + VOICE_SERVER_UPDATE EventType = "VOICE_SERVER_UPDATE" WEBHOOKS_UPDATE EventType = "WEBHOOKS_UPDATE" ) diff --git a/gateway/payloads/events/voicechannelstarttimeupdate.go b/gateway/payloads/events/voicechannelstarttimeupdate.go index d66ba1c..f278ce4 100644 --- a/gateway/payloads/events/voicechannelstarttimeupdate.go +++ b/gateway/payloads/events/voicechannelstarttimeupdate.go @@ -1,7 +1,7 @@ package events type VoiceChannelStartTimeUpdate struct { - Id uint64 `json:"id,string"` - GuildId uint64 `json:"guild_id,string"` - VoiceStartTime *int64 `json:"voice_start_time"` + Id uint64 `json:"id,string"` + GuildId uint64 `json:"guild_id,string"` + VoiceStartTime *int64 `json:"voice_start_time"` } diff --git a/rest/guild.go b/rest/guild.go index 938ffaf..d0942ce 100644 --- a/rest/guild.go +++ b/rest/guild.go @@ -887,11 +887,11 @@ func (d *SearchGuildMessagesData) Encode() string { } type SearchGuildMessagesResponse struct { - DoingDeepHistoricalIndex bool `json:"doing_deep_historical_index"` - DocumentsIndexed *int `json:"documents_indexed,omitempty"` - TotalResults int `json:"total_results"` - Messages [][]message.Message `json:"messages"` - Threads []channel.Channel `json:"threads,omitempty"` + DoingDeepHistoricalIndex bool `json:"doing_deep_historical_index"` + DocumentsIndexed *int `json:"documents_indexed,omitempty"` + TotalResults int `json:"total_results"` + Messages [][]message.Message `json:"messages"` + Threads []channel.Channel `json:"threads,omitempty"` Members []channel.ThreadMember `json:"members,omitempty"` } From 2cf967f736f4fbe73a57e37d86cfc14dadee06cd Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 28 Apr 2026 01:41:34 +0200 Subject: [PATCH 72/73] Use shared channel/application types in gateway Unify event payload types and move EventBus into the gateway package. - Renamed/moved gateway/payloads/events/eventbus.go -> gateway/eventbus.go and changed package to gateway. - Ready event now uses application.PartialApplication; added PartialApplication in objects/application/application.go. - ChannelInfo now references channel.ChannelInfoEntry; added ChannelInfoEntry to objects/channel/channel.go and removed the duplicate local struct. - Added Application json.RawMessage to Attachment and imported encoding/json. - Updated shardmanager imports and EventBus constructor usage to the new gateway EventBus. These changes remove duplicated payload structs and centralize shared types across packages. --- gateway/{payloads/events => }/eventbus.go | 2 +- gateway/payloads/events/channelinfo.go | 10 +++------- gateway/payloads/events/ready.go | 20 ++++++++------------ gateway/shardmanager.go | 5 ++--- objects/application/application.go | 5 +++++ objects/channel/attachment.go | 2 ++ objects/channel/channel.go | 6 ++++++ 7 files changed, 27 insertions(+), 23 deletions(-) rename gateway/{payloads/events => }/eventbus.go (92%) diff --git a/gateway/payloads/events/eventbus.go b/gateway/eventbus.go similarity index 92% rename from gateway/payloads/events/eventbus.go rename to gateway/eventbus.go index fc9facf..a5d7fc4 100644 --- a/gateway/payloads/events/eventbus.go +++ b/gateway/eventbus.go @@ -1,4 +1,4 @@ -package events +package gateway type EventBus struct { Listeners []interface{} diff --git a/gateway/payloads/events/channelinfo.go b/gateway/payloads/events/channelinfo.go index b1eba26..da3701c 100644 --- a/gateway/payloads/events/channelinfo.go +++ b/gateway/payloads/events/channelinfo.go @@ -1,12 +1,8 @@ package events -type ChannelInfoChannel struct { - Id uint64 `json:"id,string"` - Status *string `json:"status,omitempty"` - VoiceStartTime *int64 `json:"voice_start_time,omitempty"` -} +import "github.com/TicketsBot-cloud/gdl/objects/channel" type ChannelInfo struct { - GuildId uint64 `json:"guild_id,string"` - Channels []ChannelInfoChannel `json:"channels"` + GuildId uint64 `json:"guild_id,string"` + Channels []channel.ChannelInfoEntry `json:"channels"` } diff --git a/gateway/payloads/events/ready.go b/gateway/payloads/events/ready.go index 3d274ad..941bff4 100644 --- a/gateway/payloads/events/ready.go +++ b/gateway/payloads/events/ready.go @@ -1,21 +1,17 @@ package events import ( + "github.com/TicketsBot-cloud/gdl/objects/application" "github.com/TicketsBot-cloud/gdl/objects/guild" "github.com/TicketsBot-cloud/gdl/objects/user" ) -type ReadyApplication struct { - Id uint64 `json:"id,string"` - Flags int `json:"flags"` -} - type Ready struct { - GatewayVersion int `json:"v"` - User user.User `json:"user"` - Guilds []guild.Guild `json:"guilds"` - SessionId string `json:"session_id"` - ResumeGatewayUrl string `json:"resume_gateway_url"` - Shard []int `json:"shard"` - Application ReadyApplication `json:"application"` + GatewayVersion int `json:"v"` + User user.User `json:"user"` + Guilds []guild.Guild `json:"guilds"` + SessionId string `json:"session_id"` + ResumeGatewayUrl string `json:"resume_gateway_url"` + Shard []int `json:"shard"` + Application application.PartialApplication `json:"application"` } diff --git a/gateway/shardmanager.go b/gateway/shardmanager.go index a998230..5de518c 100644 --- a/gateway/shardmanager.go +++ b/gateway/shardmanager.go @@ -5,7 +5,6 @@ import ( "os/signal" "syscall" - "github.com/TicketsBot-cloud/gdl/gateway/payloads/events" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" "github.com/TicketsBot-cloud/gdl/rest/request" ) @@ -18,7 +17,7 @@ type ShardManager struct { ShardOptions ShardOptions Shards map[int]*Shard - EventBus *events.EventBus + EventBus *EventBus } func NewShardManager(token string, shardOptions ShardOptions) *ShardManager { @@ -30,7 +29,7 @@ func NewShardManager(token string, shardOptions ShardOptions) *ShardManager { Token: token, RateLimiter: ratelimit.NewRateLimiter(shardOptions.RateLimitStore, shardOptions.LargeShardingBuckets), ShardOptions: shardOptions, - EventBus: events.NewEventBus(), + EventBus: NewEventBus(), } manager.Shards = make(map[int]*Shard) diff --git a/objects/application/application.go b/objects/application/application.go index cf5a9c7..f0bad13 100644 --- a/objects/application/application.go +++ b/objects/application/application.go @@ -86,3 +86,8 @@ func BuildFlags(flags ...Flag) Flag { return built } + +type PartialApplication struct { + Id uint64 `json:"id,string"` + Flags int `json:"flags"` +} diff --git a/objects/channel/attachment.go b/objects/channel/attachment.go index c2ea0e3..dd90faa 100644 --- a/objects/channel/attachment.go +++ b/objects/channel/attachment.go @@ -1,6 +1,7 @@ package channel import ( + "encoding/json" "time" "github.com/TicketsBot-cloud/gdl/objects/user" @@ -35,4 +36,5 @@ type Attachment struct { Flags *AttachmentFlag `json:"flags,omitempty"` ClipParticipants []user.User `json:"clip_participants,omitempty"` ClipCreatedAt *time.Time `json:"clip_created_at,omitempty"` + Application json.RawMessage `json:"application,omitempty"` } diff --git a/objects/channel/channel.go b/objects/channel/channel.go index cf6a428..74a054b 100644 --- a/objects/channel/channel.go +++ b/objects/channel/channel.go @@ -84,3 +84,9 @@ func (c *Channel) ToPartialChannel() PartialChannel { Name: c.Name, } } + +type ChannelInfoEntry struct { + Id uint64 `json:"id,string"` + Status *string `json:"status,omitempty"` + VoiceStartTime *int64 `json:"voice_start_time,omitempty"` +} From a91faf42e748db3aa8076eeec7a4b7d0f0a03239 Mon Sep 17 00:00:00 2001 From: biast12 Date: Tue, 28 Apr 2026 19:09:44 +0200 Subject: [PATCH 73/73] Various cleanup: APIs, context, and rate limits Several small refactors and fixes across the codebase: - Use strings.EqualFold for case-insensitive comparisons in command handling. - Defer rows.Close() after error check in PG cache query. - Replace ioutil.ReadAll with io.ReadAll and remove unused import. - Use time.Until for TTL calculations and global reset times in MemoryStore. - Simplify Redis store ContextBuilder to return Background context. - Replace nested if/else with switch for Content-Type encoding in Endpoint.Request. - Use Multipart writer String() when building multipart payloads. - Update example apps to use MemoryCacheFactory, add context.Context to shard REST calls, and simplify avatar example to send URL instead of fetching file. - Adjust reaction handling (emoji name pointer deref) and add context to CreateMessageEmbed/GetChannelMessage/GetReactions in starboard example. - Remove os.Kill from WaitForInterrupt signal.Notify. - Minor test update: expect ComponentStringSelect in interaction deserialization test. - Remove an extraneous comment line in ratelimiter. These changes improve correctness, modernize APIs, and reduce potential panics/resource leaks. --- cache/pgcache.go | 2 +- command/commandhandler.go | 8 ++++---- examples/avatar/avatar.go | 27 ++++--------------------- examples/starboard/starboard.go | 17 +++++++--------- gateway/shardmanager.go | 2 +- gateway/wrappedreader.go | 3 +-- rest/ratelimit/memorystore.go | 4 ++-- rest/ratelimit/ratelimiter.go | 2 -- rest/ratelimit/redisstore.go | 3 +-- rest/request/endpoint.go | 7 ++++--- rest/request/multipart.go | 2 +- test/interactiondeserialization_test.go | 2 +- 12 files changed, 27 insertions(+), 52 deletions(-) diff --git a/cache/pgcache.go b/cache/pgcache.go index 6a25de0..fe3537b 100644 --- a/cache/pgcache.go +++ b/cache/pgcache.go @@ -367,10 +367,10 @@ func (c *PgCache) GetGuildChannels(ctx context.Context, guildId uint64) ([]chann } rows, err := c.Query(ctx, queryGetGuildChannels, guildId) - defer rows.Close() if err != nil { return nil, err } + defer rows.Close() var channels []channel.Channel for rows.Next() { diff --git a/command/commandhandler.go b/command/commandhandler.go index 82acb53..f998855 100644 --- a/command/commandhandler.go +++ b/command/commandhandler.go @@ -59,12 +59,12 @@ func (h *CommandHandler) commandListener(s *gateway.Shard, e *events.MessageCrea } for _, cmd := range h.commands { - match := strings.ToLower(cmd.Name) == strings.ToLower(root) + match := strings.EqualFold(cmd.Name, root) // check aliases if !match { for _, alias := range cmd.Aliases { - if strings.ToLower(cmd.Name) == strings.ToLower(alias) { + if strings.EqualFold(cmd.Name, alias) { match = true break } @@ -76,12 +76,12 @@ func (h *CommandHandler) commandListener(s *gateway.Shard, e *events.MessageCrea argloop: for i, arg := range args { for _, sub := range cmd.SubCommands { - subMatch := strings.ToLower(arg) == strings.ToLower(sub.Name) + subMatch := strings.EqualFold(arg, sub.Name) // check aliases if !subMatch { for _, alias := range sub.Aliases { - if strings.ToLower(arg) == strings.ToLower(alias) { + if strings.EqualFold(arg, alias) { subMatch = true break } diff --git a/examples/avatar/avatar.go b/examples/avatar/avatar.go index c8b51bc..0e7ecf3 100644 --- a/examples/avatar/avatar.go +++ b/examples/avatar/avatar.go @@ -1,25 +1,19 @@ package main import ( + "context" "fmt" - "net/http" "github.com/TicketsBot-cloud/gdl/cache" "github.com/TicketsBot-cloud/gdl/command" "github.com/TicketsBot-cloud/gdl/gateway" - "github.com/TicketsBot-cloud/gdl/rest" "github.com/TicketsBot-cloud/gdl/rest/ratelimit" "github.com/sirupsen/logrus" ) func main() { - cacheFactory := cache.BoltCacheFactory(cache.CacheOptions{ + cacheFactory := cache.MemoryCacheFactory(cache.CacheOptions{ Users: true, - }, cache.BoltOptions{ - ClearOnRestart: false, - Path: "bolt.db", - FileMode: 600, - Options: nil, }) shardOptions := gateway.ShardOptions{ @@ -55,27 +49,14 @@ func registerCommands(sm *gateway.ShardManager) { func onCommand(ctx command.CommandContext) { if len(ctx.Mentions) == 0 { - _, _ = ctx.Shard.CreateMessage(ctx.ChannelId, "You need to mention a user") + _, _ = ctx.Shard.CreateMessage(context.Background(), ctx.ChannelId, "You need to mention a user") return } for _, mention := range ctx.Mentions { - res, err := http.Get(mention.AvatarUrl(2048)) + _, err := ctx.Shard.CreateMessage(context.Background(), ctx.ChannelId, fmt.Sprintf("%s's avatar is: %s", mention.Username, mention.AvatarUrl(2048))) if err != nil { logrus.Warn(err.Error()) - continue } - defer res.Body.Close() - - data := rest.CreateMessageData{ - Content: fmt.Sprintf("%s's avatar is:", mention.Username), - File: &rest.File{ - Name: "avatar.png", - ContentType: res.Header.Get("Content-Type"), - Reader: res.Body, - }, - } - - ctx.Shard.CreateMessageComplex(ctx.ChannelId, data) } } diff --git a/examples/starboard/starboard.go b/examples/starboard/starboard.go index fbb6134..cfeafee 100644 --- a/examples/starboard/starboard.go +++ b/examples/starboard/starboard.go @@ -1,6 +1,8 @@ package main import ( + "context" + "github.com/TicketsBot-cloud/gdl/cache" "github.com/TicketsBot-cloud/gdl/gateway" "github.com/TicketsBot-cloud/gdl/gateway/payloads/events" @@ -16,14 +18,9 @@ const ( ) func main() { - cacheFactory := cache.BoltCacheFactory(cache.CacheOptions{ + cacheFactory := cache.MemoryCacheFactory(cache.CacheOptions{ Guilds: true, Users: true, - }, cache.BoltOptions{ - ClearOnRestart: false, - Path: "bolt.db", - FileMode: 600, - Options: nil, }) shardOptions := gateway.ShardOptions{ @@ -47,12 +44,12 @@ func main() { func reactListener(s *gateway.Shard, e *events.MessageReactionAdd) { // check the new reaction is a star - if e.Emoji.Name != "⭐" { + if *e.Emoji.Name != "⭐" { return } // get people who have reacted with a star so we can check if we've met the threshold - reactors, err := s.GetReactions(e.ChannelId, e.MessageId, "⭐", rest.GetReactionsData{}) + reactors, err := s.GetReactions(context.Background(), e.ChannelId, e.MessageId, "⭐", rest.GetReactionsData{}) if err != nil { logrus.Warn(err) return @@ -60,7 +57,7 @@ func reactListener(s *gateway.Shard, e *events.MessageReactionAdd) { if len(reactors) >= StarThreshold { // get the message object so we can get the content & sender - msg, err := s.GetChannelMessage(e.ChannelId, e.MessageId) + msg, err := s.GetChannelMessage(context.Background(), e.ChannelId, e.MessageId) if err != nil { logrus.Warn(err) return @@ -72,7 +69,7 @@ func reactListener(s *gateway.Shard, e *events.MessageReactionAdd) { SetAuthor(msg.Author.Username, "", msg.Author.AvatarUrl(256)). SetDescription(msg.Content) - if _, err := s.CreateMessageEmbed(StarboardChannelId, embed); err != nil { + if _, err := s.CreateMessageEmbed(context.Background(), StarboardChannelId, embed); err != nil { logrus.Warn(err) return } diff --git a/gateway/shardmanager.go b/gateway/shardmanager.go index 5de518c..a8565a8 100644 --- a/gateway/shardmanager.go +++ b/gateway/shardmanager.go @@ -66,6 +66,6 @@ func (sm *ShardManager) ShardForGuild(guildId uint64) *Shard { func (sm *ShardManager) WaitForInterrupt() { ch := make(chan os.Signal, 1) - signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) + signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-ch } diff --git a/gateway/wrappedreader.go b/gateway/wrappedreader.go index 4acecc5..c917e3f 100644 --- a/gateway/wrappedreader.go +++ b/gateway/wrappedreader.go @@ -4,7 +4,6 @@ import ( "errors" "github.com/tatsuworks/czlib" "io" - "io/ioutil" "sync" ) @@ -43,7 +42,7 @@ func (r *wrappedReader) Read() ([]byte, error) { case <-r.closeChan: return nil, errors.New("reader was closed") default: - return ioutil.ReadAll(r.ReadCloser) + return io.ReadAll(r.ReadCloser) } } diff --git a/rest/ratelimit/memorystore.go b/rest/ratelimit/memorystore.go index 10ff8aa..d66b148 100644 --- a/rest/ratelimit/memorystore.go +++ b/rest/ratelimit/memorystore.go @@ -43,7 +43,7 @@ func (s *MemoryStore) getTTLAndDecrease(route Route) (time.Duration, error) { if found { remaining := item.Data.(int) - ttl := item.ExpireAt.Sub(time.Now()) + ttl := time.Until(item.ExpireAt) if remaining > 0 { s.Cache.SetWithTTL(key, remaining-1, ttl) @@ -59,7 +59,7 @@ func (s *MemoryStore) getTTLAndDecrease(route Route) (time.Duration, error) { func (s *MemoryStore) getGlobalTTL() (time.Duration, error) { s.globalLock.RLock() defer s.globalLock.RUnlock() - return s.globalResetAfter.Sub(time.Now()), nil + return time.Until(s.globalResetAfter), nil } func (s *MemoryStore) UpdateRateLimit(route Route, remaining int, resetAfter time.Duration) error { diff --git a/rest/ratelimit/ratelimiter.go b/rest/ratelimit/ratelimiter.go index b1d5f46..20c3973 100644 --- a/rest/ratelimit/ratelimiter.go +++ b/rest/ratelimit/ratelimiter.go @@ -5,8 +5,6 @@ import ( "time" ) -// Big thanks to https://github.com/spencersharkey for sharing his ratelimiter with me - type Ratelimiter struct { sync.Mutex Store RateLimitStore diff --git a/rest/ratelimit/redisstore.go b/rest/ratelimit/redisstore.go index 0a83da1..df5f579 100644 --- a/rest/ratelimit/redisstore.go +++ b/rest/ratelimit/redisstore.go @@ -19,8 +19,7 @@ func NewRedisStore(client *redis.Client, keyPrefix string) *RedisStore { Client: client, keyPrefix: keyPrefix, ContextBuilder: func() context.Context { - ctx, _ := context.WithTimeout(context.Background(), time.Second*5) - return ctx + return context.Background() }, } } diff --git a/rest/request/endpoint.go b/rest/request/endpoint.go index 235b70d..7ed58c9 100644 --- a/rest/request/endpoint.go +++ b/rest/request/endpoint.go @@ -107,19 +107,20 @@ func (e *Endpoint) Request(ctx context.Context, token string, body any, response // Encode body var encoded []byte - if e.ContentType == ApplicationJson { + switch e.ContentType { + case ApplicationJson: raw, err := json.Marshal(&body) if err != nil { return err, nil } encoded = raw - } else if e.ContentType == ApplicationFormUrlEncoded { + case ApplicationFormUrlEncoded: str, err := qs.Marshal(body) if err != nil { return err, nil } encoded = []byte(str) - } else if e.ContentType == MultipartFormData { + case MultipartFormData: data, ok := body.(MultipartPayload) if !ok { return errors.New("Content-Type MultipartFormData specified but EncodeMultipartFormData was missing"), nil diff --git a/rest/request/multipart.go b/rest/request/multipart.go index 921c9fd..ca751f9 100644 --- a/rest/request/multipart.go +++ b/rest/request/multipart.go @@ -58,5 +58,5 @@ func EncodeMultipartFormData(payload MultipartPayload) ([]byte, string, error) { } } - return []byte(string(body.Bytes()) + "\r\n--" + writer.Boundary() + "--"), writer.Boundary(), nil + return []byte(body.String() + "\r\n--" + writer.Boundary() + "--"), writer.Boundary(), nil } diff --git a/test/interactiondeserialization_test.go b/test/interactiondeserialization_test.go index dc0c60f..37f3bf1 100644 --- a/test/interactiondeserialization_test.go +++ b/test/interactiondeserialization_test.go @@ -28,7 +28,7 @@ func TestDeserializeSelectMenuInteraction(t *testing.T) { return } - MustMatch(t, "interaction type", i.Data.Type(), component.ComponentSelectMenu) + MustMatch(t, "interaction type", i.Data.Type(), component.ComponentStringSelect) data := i.Data.AsSelectMenu() MustMatch(t, "custom id", data.CustomId, "class_select_1")