Add Guild Scheduled Event Support (#1032)

* Add Guild Scheduled Events support

* Add missing Indents for Guild Scheduled Events

* fix: Do update from new schedules updates and repository updates

* doc: Add missing documentation on const

* doc: Add missing documentation on events struct

* tests: Add a Skip condition when dgBot is not set to prevent segfault

* fix: Somes changes following the last review steps

* docs: Add an example to manipulate GuildScheduledEvent

* clean: Remove useless pointers on struct used to retrieve data

* tests: Test extra query params on GuildScheduledEventUsers requests

* clean: Remove unused variables

* feat: Add nullable types to provide null value to Discord API when is necessary

* feat: Use NullableString in ScheduledEvents

* docs: Add example for usage of NullableString

* Update structs.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* Update restapi.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* fix: Review changes to move back nullable string into a simple MarshalJSON

* fix: Remove NullString on tests and examples

* doc: Add missing doc

* Update structs.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* fix: misunderstood MarhsalJSON

* fix: Follow the convention of discordgo on url.Values

* Update examples/scheduled_events/main.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* changes: use conditional instead on Sprintf

* fix: Add missing status on Params

* Update structs.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* Update structs.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* changes: Move flag.Parse inside the init function

* fix: remove null statement of test suite

* fix: Rewrite Marshal of GuildScheduledEventParams to prevent a stack overflow on marshall same type

* clean: Remove unused Intents

* Update restapi.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* Update restapi.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* Update restapi.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* doc: polish the documentation

* clean: Final polish code

* doc: Add information about 1:1 usage

* Update discord_test.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* doc: remove unnecessary additional infos

* Update structs.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* Update discord_test.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* Update restapi.go

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>

* chore(examples/scheduled_events): removed NullString comment

* fix(structs): grammar in comment to EntityType

* fix: run gofmt

Co-authored-by: Fedor Lapshin <fe.lap.prog@gmail.com>
This commit is contained in:
42Atomys 2022-02-27 16:22:31 +01:00 committed by GitHub
parent 5056d53d17
commit 9448b0eb96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 640 additions and 92 deletions

View file

@ -15,11 +15,12 @@ var (
dg *Session // Stores a global discordgo user session dg *Session // Stores a global discordgo user session
dgBot *Session // Stores a global discordgo bot session dgBot *Session // Stores a global discordgo bot session
envOAuth2Token = os.Getenv("DG_OAUTH2_TOKEN") // Token to use when authenticating using OAuth2 token envOAuth2Token = os.Getenv("DG_OAUTH2_TOKEN") // Token to use when authenticating using OAuth2 token
envBotToken = os.Getenv("DGB_TOKEN") // Token to use when authenticating the bot account envBotToken = os.Getenv("DGB_TOKEN") // Token to use when authenticating the bot account
envGuild = os.Getenv("DG_GUILD") // Guild ID to use for tests envGuild = os.Getenv("DG_GUILD") // Guild ID to use for tests
envChannel = os.Getenv("DG_CHANNEL") // Channel ID to use for tests envChannel = os.Getenv("DG_CHANNEL") // Channel ID to use for tests
envAdmin = os.Getenv("DG_ADMIN") // User ID of admin user to use for tests envVoiceChannel = os.Getenv("DG_VOICE_CHANNEL") // Channel ID to use for tests
envAdmin = os.Getenv("DG_ADMIN") // User ID of admin user to use for tests
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -183,3 +184,119 @@ func TestRemoveHandler(t *testing.T) {
t.Fatalf("testHandler was not called once.") t.Fatalf("testHandler was not called once.")
} }
} }
func TestScheduledEvents(t *testing.T) {
if dgBot == nil {
t.Skip("Skipping, dgBot not set.")
}
beginAt := time.Now().Add(1 * time.Hour)
endAt := time.Now().Add(2 * time.Hour)
event, err := dgBot.GuildScheduledEventCreate(envGuild, &GuildScheduledEventParams{
Name: "Test Event",
PrivacyLevel: GuildScheduledEventPrivacyLevelGuildOnly,
ScheduledStartTime: &beginAt,
ScheduledEndTime: &endAt,
Description: "Awesome Test Event created on livestream",
EntityType: GuildScheduledEventEntityTypeExternal,
EntityMetadata: &GuildScheduledEventEntityMetadata{
Location: "https://discord.com",
},
})
defer dgBot.GuildScheduledEventDelete(envGuild, event.ID)
if err != nil || event.Name != "Test Event" {
t.Fatal(err)
}
events, err := dgBot.GuildScheduledEvents(envGuild, true)
if err != nil {
t.Fatal(err)
}
var foundEvent *GuildScheduledEvent
for _, e := range events {
if e.ID == event.ID {
foundEvent = e
break
}
}
if foundEvent.Name != event.Name {
t.Fatal("err on GuildScheduledEvents endpoint. Missing Scheduled Event")
}
getEvent, err := dgBot.GuildScheduledEvent(envGuild, event.ID, true)
if err != nil {
t.Fatal(err)
}
if getEvent.Name != event.Name {
t.Fatal("err on GuildScheduledEvent endpoint. Mismatched Scheduled Event")
}
eventUpdated, err := dgBot.GuildScheduledEventEdit(envGuild, event.ID, &GuildScheduledEventParams{Name: "Test Event Updated"})
if err != nil {
t.Fatal(err)
}
if eventUpdated.Name != "Test Event Updated" {
t.Fatal("err on GuildScheduledEventUpdate endpoint. Scheduled Event Name mismatch")
}
// Usage of 1 and 1 is just the pseudo data with the purpose to run all branches in the function without crashes.
// see https://github.com/bwmarrin/discordgo/pull/1032#discussion_r815438303 for more details.
users, err := dgBot.GuildScheduledEventUsers(envGuild, event.ID, 1, true, "1", "1")
if err != nil {
t.Fatal(err)
}
if len(users) != 0 {
t.Fatal("err on GuildScheduledEventUsers. Mismatch of event maybe occured")
}
err = dgBot.GuildScheduledEventDelete(envGuild, event.ID)
if err != nil {
t.Fatal(err)
}
}
func TestComplexScheduledEvents(t *testing.T) {
if dgBot == nil {
t.Skip("Skipping, dgBot not set.")
}
beginAt := time.Now().Add(1 * time.Hour)
endAt := time.Now().Add(2 * time.Hour)
event, err := dgBot.GuildScheduledEventCreate(envGuild, &GuildScheduledEventParams{
Name: "Test Voice Event",
PrivacyLevel: GuildScheduledEventPrivacyLevelGuildOnly,
ScheduledStartTime: &beginAt,
ScheduledEndTime: &endAt,
Description: "Test event on voice channel",
EntityType: GuildScheduledEventEntityTypeVoice,
ChannelID: envVoiceChannel,
})
if err != nil || event.Name != "Test Voice Event" {
t.Fatal(err)
}
defer dgBot.GuildScheduledEventDelete(envGuild, event.ID)
_, err = dgBot.GuildScheduledEventEdit(envGuild, event.ID, &GuildScheduledEventParams{
EntityType: GuildScheduledEventEntityTypeExternal,
EntityMetadata: &GuildScheduledEventEntityMetadata{
Location: "https://discord.com",
},
})
if err != nil {
t.Fatal("err on GuildScheduledEventEdit. Change of entity type to external failed")
}
_, err = dgBot.GuildScheduledEventEdit(envGuild, event.ID, &GuildScheduledEventParams{
ChannelID: envVoiceChannel,
EntityType: GuildScheduledEventEntityTypeVoice,
EntityMetadata: nil,
})
if err != nil {
t.Fatal("err on GuildScheduledEventEdit. Change of entity type to voice failed")
}
}

View file

@ -60,38 +60,41 @@ var (
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" } EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" } EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
EndpointGuild = func(gID string) string { return EndpointGuilds + gID } EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
EndpointGuildThreads = func(gID string) string { return EndpointGuild(gID) + "/threads" } EndpointGuildThreads = func(gID string) string { return EndpointGuild(gID) + "/threads" }
EndpointGuildActiveThreads = func(gID string) string { return EndpointGuildThreads(gID) + "/active" } EndpointGuildActiveThreads = func(gID string) string { return EndpointGuildThreads(gID) + "/active" }
EndpointGuildPreview = func(gID string) string { return EndpointGuilds + gID + "/preview" } EndpointGuildPreview = func(gID string) string { return EndpointGuilds + gID + "/preview" }
EndpointGuildChannels = func(gID string) string { return EndpointGuilds + gID + "/channels" } EndpointGuildChannels = func(gID string) string { return EndpointGuilds + gID + "/channels" }
EndpointGuildMembers = func(gID string) string { return EndpointGuilds + gID + "/members" } EndpointGuildMembers = func(gID string) string { return EndpointGuilds + gID + "/members" }
EndpointGuildMember = func(gID, uID string) string { return EndpointGuilds + gID + "/members/" + uID } EndpointGuildMember = func(gID, uID string) string { return EndpointGuilds + gID + "/members/" + uID }
EndpointGuildMemberRole = func(gID, uID, rID string) string { return EndpointGuilds + gID + "/members/" + uID + "/roles/" + rID } EndpointGuildMemberRole = func(gID, uID, rID string) string { return EndpointGuilds + gID + "/members/" + uID + "/roles/" + rID }
EndpointGuildBans = func(gID string) string { return EndpointGuilds + gID + "/bans" } EndpointGuildBans = func(gID string) string { return EndpointGuilds + gID + "/bans" }
EndpointGuildBan = func(gID, uID string) string { return EndpointGuilds + gID + "/bans/" + uID } EndpointGuildBan = func(gID, uID string) string { return EndpointGuilds + gID + "/bans/" + uID }
EndpointGuildIntegrations = func(gID string) string { return EndpointGuilds + gID + "/integrations" } EndpointGuildIntegrations = func(gID string) string { return EndpointGuilds + gID + "/integrations" }
EndpointGuildIntegration = func(gID, iID string) string { return EndpointGuilds + gID + "/integrations/" + iID } EndpointGuildIntegration = func(gID, iID string) string { return EndpointGuilds + gID + "/integrations/" + iID }
EndpointGuildRoles = func(gID string) string { return EndpointGuilds + gID + "/roles" } EndpointGuildRoles = func(gID string) string { return EndpointGuilds + gID + "/roles" }
EndpointGuildRole = func(gID, rID string) string { return EndpointGuilds + gID + "/roles/" + rID } EndpointGuildRole = func(gID, rID string) string { return EndpointGuilds + gID + "/roles/" + rID }
EndpointGuildInvites = func(gID string) string { return EndpointGuilds + gID + "/invites" } EndpointGuildInvites = func(gID string) string { return EndpointGuilds + gID + "/invites" }
EndpointGuildWidget = func(gID string) string { return EndpointGuilds + gID + "/widget" } EndpointGuildWidget = func(gID string) string { return EndpointGuilds + gID + "/widget" }
EndpointGuildEmbed = EndpointGuildWidget EndpointGuildEmbed = EndpointGuildWidget
EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" } EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" }
EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" } EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" } EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" }
EndpointGuildSplash = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" } EndpointGuildSplash = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" }
EndpointGuildWebhooks = func(gID string) string { return EndpointGuilds + gID + "/webhooks" } EndpointGuildWebhooks = func(gID string) string { return EndpointGuilds + gID + "/webhooks" }
EndpointGuildAuditLogs = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" } EndpointGuildAuditLogs = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" }
EndpointGuildEmojis = func(gID string) string { return EndpointGuilds + gID + "/emojis" } EndpointGuildEmojis = func(gID string) string { return EndpointGuilds + gID + "/emojis" }
EndpointGuildEmoji = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID } EndpointGuildEmoji = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID }
EndpointGuildBanner = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" } EndpointGuildBanner = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" }
EndpointGuildStickers = func(gID string) string { return EndpointGuilds + gID + "/stickers" } EndpointGuildStickers = func(gID string) string { return EndpointGuilds + gID + "/stickers" }
EndpointGuildSticker = func(gID, sID string) string { return EndpointGuilds + gID + "/stickers/" + sID } EndpointGuildSticker = func(gID, sID string) string { return EndpointGuilds + gID + "/stickers/" + sID }
EndpointGuildTemplate = func(tID string) string { return EndpointGuilds + "/templates/" + tID } EndpointGuildScheduledEvents = func(gID string) string { return EndpointGuilds + gID + "/scheduled-events" }
EndpointGuildTemplates = func(gID string) string { return EndpointGuilds + gID + "/templates" } EndpointGuildScheduledEvent = func(gID, eID string) string { return EndpointGuilds + gID + "/scheduled-events/" + eID }
EndpointGuildTemplateSync = func(gID, tID string) string { return EndpointGuilds + gID + "/templates/" + tID } EndpointGuildScheduledEventUsers = func(gID, eID string) string { return EndpointGuildScheduledEvent(gID, eID) + "/users" }
EndpointGuildMemberAvatar = func(gId, uID, aID string) string { EndpointGuildTemplate = func(tID string) string { return EndpointGuilds + "/templates/" + tID }
EndpointGuildTemplates = func(gID string) string { return EndpointGuilds + gID + "/templates" }
EndpointGuildTemplateSync = func(gID, tID string) string { return EndpointGuilds + gID + "/templates/" + tID }
EndpointGuildMemberAvatar = func(gId, uID, aID string) string {
return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".png" return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".png"
} }
EndpointGuildMemberAvatarAnimated = func(gId, uID, aID string) string { EndpointGuildMemberAvatarAnimated = func(gId, uID, aID string) string {

View file

@ -7,59 +7,62 @@ package discordgo
// Event type values are used to match the events returned by Discord. // Event type values are used to match the events returned by Discord.
// EventTypes surrounded by __ are synthetic and are internal to DiscordGo. // EventTypes surrounded by __ are synthetic and are internal to DiscordGo.
const ( const (
channelCreateEventType = "CHANNEL_CREATE" channelCreateEventType = "CHANNEL_CREATE"
channelDeleteEventType = "CHANNEL_DELETE" channelDeleteEventType = "CHANNEL_DELETE"
channelPinsUpdateEventType = "CHANNEL_PINS_UPDATE" channelPinsUpdateEventType = "CHANNEL_PINS_UPDATE"
channelUpdateEventType = "CHANNEL_UPDATE" channelUpdateEventType = "CHANNEL_UPDATE"
connectEventType = "__CONNECT__" connectEventType = "__CONNECT__"
disconnectEventType = "__DISCONNECT__" disconnectEventType = "__DISCONNECT__"
eventEventType = "__EVENT__" eventEventType = "__EVENT__"
guildBanAddEventType = "GUILD_BAN_ADD" guildBanAddEventType = "GUILD_BAN_ADD"
guildBanRemoveEventType = "GUILD_BAN_REMOVE" guildBanRemoveEventType = "GUILD_BAN_REMOVE"
guildCreateEventType = "GUILD_CREATE" guildCreateEventType = "GUILD_CREATE"
guildDeleteEventType = "GUILD_DELETE" guildDeleteEventType = "GUILD_DELETE"
guildEmojisUpdateEventType = "GUILD_EMOJIS_UPDATE" guildEmojisUpdateEventType = "GUILD_EMOJIS_UPDATE"
guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE" guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE"
guildMemberAddEventType = "GUILD_MEMBER_ADD" guildMemberAddEventType = "GUILD_MEMBER_ADD"
guildMemberRemoveEventType = "GUILD_MEMBER_REMOVE" guildMemberRemoveEventType = "GUILD_MEMBER_REMOVE"
guildMemberUpdateEventType = "GUILD_MEMBER_UPDATE" guildMemberUpdateEventType = "GUILD_MEMBER_UPDATE"
guildMembersChunkEventType = "GUILD_MEMBERS_CHUNK" guildMembersChunkEventType = "GUILD_MEMBERS_CHUNK"
guildRoleCreateEventType = "GUILD_ROLE_CREATE" guildRoleCreateEventType = "GUILD_ROLE_CREATE"
guildRoleDeleteEventType = "GUILD_ROLE_DELETE" guildRoleDeleteEventType = "GUILD_ROLE_DELETE"
guildRoleUpdateEventType = "GUILD_ROLE_UPDATE" guildRoleUpdateEventType = "GUILD_ROLE_UPDATE"
guildUpdateEventType = "GUILD_UPDATE" guildUpdateEventType = "GUILD_UPDATE"
interactionCreateEventType = "INTERACTION_CREATE" guildScheduledEventCreateEventType = "GUILD_SCHEDULED_EVENT_CREATE"
inviteCreateEventType = "INVITE_CREATE" guildScheduledEventUpdateEventType = "GUILD_SCHEDULED_EVENT_UPDATE"
inviteDeleteEventType = "INVITE_DELETE" guildScheduledEventDeleteEventType = "GUILD_SCHEDULED_EVENT_DELETE"
messageAckEventType = "MESSAGE_ACK" interactionCreateEventType = "INTERACTION_CREATE"
messageCreateEventType = "MESSAGE_CREATE" inviteCreateEventType = "INVITE_CREATE"
messageDeleteEventType = "MESSAGE_DELETE" inviteDeleteEventType = "INVITE_DELETE"
messageDeleteBulkEventType = "MESSAGE_DELETE_BULK" messageAckEventType = "MESSAGE_ACK"
messageReactionAddEventType = "MESSAGE_REACTION_ADD" messageCreateEventType = "MESSAGE_CREATE"
messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE" messageDeleteEventType = "MESSAGE_DELETE"
messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL" messageDeleteBulkEventType = "MESSAGE_DELETE_BULK"
messageUpdateEventType = "MESSAGE_UPDATE" messageReactionAddEventType = "MESSAGE_REACTION_ADD"
presenceUpdateEventType = "PRESENCE_UPDATE" messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE"
presencesReplaceEventType = "PRESENCES_REPLACE" messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL"
rateLimitEventType = "__RATE_LIMIT__" messageUpdateEventType = "MESSAGE_UPDATE"
readyEventType = "READY" presenceUpdateEventType = "PRESENCE_UPDATE"
relationshipAddEventType = "RELATIONSHIP_ADD" presencesReplaceEventType = "PRESENCES_REPLACE"
relationshipRemoveEventType = "RELATIONSHIP_REMOVE" rateLimitEventType = "__RATE_LIMIT__"
resumedEventType = "RESUMED" readyEventType = "READY"
threadCreateEventType = "THREAD_CREATE" relationshipAddEventType = "RELATIONSHIP_ADD"
threadDeleteEventType = "THREAD_DELETE" relationshipRemoveEventType = "RELATIONSHIP_REMOVE"
threadListSyncEventType = "THREAD_LIST_SYNC" resumedEventType = "RESUMED"
threadMemberUpdateEventType = "THREAD_MEMBER_UPDATE" threadCreateEventType = "THREAD_CREATE"
threadMembersUpdateEventType = "THREAD_MEMBERS_UPDATE" threadDeleteEventType = "THREAD_DELETE"
threadUpdateEventType = "THREAD_UPDATE" threadListSyncEventType = "THREAD_LIST_SYNC"
typingStartEventType = "TYPING_START" threadMemberUpdateEventType = "THREAD_MEMBER_UPDATE"
userGuildSettingsUpdateEventType = "USER_GUILD_SETTINGS_UPDATE" threadMembersUpdateEventType = "THREAD_MEMBERS_UPDATE"
userNoteUpdateEventType = "USER_NOTE_UPDATE" threadUpdateEventType = "THREAD_UPDATE"
userSettingsUpdateEventType = "USER_SETTINGS_UPDATE" typingStartEventType = "TYPING_START"
userUpdateEventType = "USER_UPDATE" userGuildSettingsUpdateEventType = "USER_GUILD_SETTINGS_UPDATE"
voiceServerUpdateEventType = "VOICE_SERVER_UPDATE" userNoteUpdateEventType = "USER_NOTE_UPDATE"
voiceStateUpdateEventType = "VOICE_STATE_UPDATE" userSettingsUpdateEventType = "USER_SETTINGS_UPDATE"
webhooksUpdateEventType = "WEBHOOKS_UPDATE" userUpdateEventType = "USER_UPDATE"
voiceServerUpdateEventType = "VOICE_SERVER_UPDATE"
voiceStateUpdateEventType = "VOICE_STATE_UPDATE"
webhooksUpdateEventType = "WEBHOOKS_UPDATE"
) )
// channelCreateEventHandler is an event handler for ChannelCreate events. // channelCreateEventHandler is an event handler for ChannelCreate events.
@ -307,6 +310,66 @@ func (eh guildIntegrationsUpdateEventHandler) Handle(s *Session, i interface{})
} }
} }
// guildScheduledEventCreateEventHandler is an event handler for GuildScheduledEventCreate events.
type guildScheduledEventCreateEventHandler func(*Session, *GuildScheduledEventCreate)
// Type returns the event type for GuildScheduledEventCreate events.
func (eh guildScheduledEventCreateEventHandler) Type() string {
return guildScheduledEventCreateEventType
}
// New returns a new instance of GuildScheduledEventCreate.
func (eh guildScheduledEventCreateEventHandler) New() interface{} {
return &GuildScheduledEventCreate{}
}
// Handle is the handler for GuildScheduledEventCreate events.
func (eh guildScheduledEventCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventCreate); ok {
eh(s, t)
}
}
// guildScheduledEventUpdateEventHandler is an event handler for GuildScheduledEventUpdate events.
type guildScheduledEventUpdateEventHandler func(*Session, *GuildScheduledEventUpdate)
// Type returns the event type for GuildScheduledEventUpdate events.
func (eh guildScheduledEventUpdateEventHandler) Type() string {
return guildScheduledEventUpdateEventType
}
// New returns a new instance of GuildScheduledEventUpdate.
func (eh guildScheduledEventUpdateEventHandler) New() interface{} {
return &GuildScheduledEventUpdate{}
}
// Handle is the handler for GuildScheduledEventUpdate events.
func (eh guildScheduledEventUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventUpdate); ok {
eh(s, t)
}
}
// guildScheduledEventDeleteEventHandler is an event handler for GuildScheduledEventDelete events.
type guildScheduledEventDeleteEventHandler func(*Session, *GuildScheduledEventDelete)
// Type returns the event type for GuildScheduledEventDelete events.
func (eh guildScheduledEventDeleteEventHandler) Type() string {
return guildScheduledEventDeleteEventType
}
// New returns a new instance of GuildScheduledEventDelete.
func (eh guildScheduledEventDeleteEventHandler) New() interface{} {
return &GuildScheduledEventDelete{}
}
// Handle is the handler for GuildScheduledEventDelete events.
func (eh guildScheduledEventDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventDelete); ok {
eh(s, t)
}
}
// guildMemberAddEventHandler is an event handler for GuildMemberAdd events. // guildMemberAddEventHandler is an event handler for GuildMemberAdd events.
type guildMemberAddEventHandler func(*Session, *GuildMemberAdd) type guildMemberAddEventHandler func(*Session, *GuildMemberAdd)
@ -1132,6 +1195,12 @@ func handlerForInterface(handler interface{}) EventHandler {
return guildEmojisUpdateEventHandler(v) return guildEmojisUpdateEventHandler(v)
case func(*Session, *GuildIntegrationsUpdate): case func(*Session, *GuildIntegrationsUpdate):
return guildIntegrationsUpdateEventHandler(v) return guildIntegrationsUpdateEventHandler(v)
case func(*Session, *GuildScheduledEventCreate):
return guildScheduledEventCreateEventHandler(v)
case func(*Session, *GuildScheduledEventUpdate):
return guildScheduledEventUpdateEventHandler(v)
case func(*Session, *GuildScheduledEventDelete):
return guildScheduledEventDeleteEventHandler(v)
case func(*Session, *GuildMemberAdd): case func(*Session, *GuildMemberAdd):
return guildMemberAddEventHandler(v) return guildMemberAddEventHandler(v)
case func(*Session, *GuildMemberRemove): case func(*Session, *GuildMemberRemove):
@ -1228,6 +1297,9 @@ func init() {
registerInterfaceProvider(guildDeleteEventHandler(nil)) registerInterfaceProvider(guildDeleteEventHandler(nil))
registerInterfaceProvider(guildEmojisUpdateEventHandler(nil)) registerInterfaceProvider(guildEmojisUpdateEventHandler(nil))
registerInterfaceProvider(guildIntegrationsUpdateEventHandler(nil)) registerInterfaceProvider(guildIntegrationsUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventCreateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventDeleteEventHandler(nil))
registerInterfaceProvider(guildMemberAddEventHandler(nil)) registerInterfaceProvider(guildMemberAddEventHandler(nil))
registerInterfaceProvider(guildMemberRemoveEventHandler(nil)) registerInterfaceProvider(guildMemberRemoveEventHandler(nil))
registerInterfaceProvider(guildMemberUpdateEventHandler(nil)) registerInterfaceProvider(guildMemberUpdateEventHandler(nil))

View file

@ -199,6 +199,21 @@ type GuildIntegrationsUpdate struct {
GuildID string `json:"guild_id"` GuildID string `json:"guild_id"`
} }
// GuildScheduledEventCreate is the data for a GuildScheduledEventCreate event.
type GuildScheduledEventCreate struct {
*GuildScheduledEvent
}
// GuildScheduledEventUpdate is the data for a GuildScheduledEventUpdate event.
type GuildScheduledEventUpdate struct {
*GuildScheduledEvent
}
// GuildScheduledEventDelete is the data for a GuildScheduledEventDelete event.
type GuildScheduledEventDelete struct {
*GuildScheduledEvent
}
// MessageAck is the data for a MessageAck event. // MessageAck is the data for a MessageAck event.
type MessageAck struct { type MessageAck struct {
MessageID string `json:"message_id"` MessageID string `json:"message_id"`

View file

@ -0,0 +1,84 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"time"
"github.com/bwmarrin/discordgo"
)
// Flags
var (
GuildID = flag.String("guild", "", "Test guild ID")
VoiceChannelID = flag.String("voice", "", "Test voice channel ID")
BotToken = flag.String("token", "", "Bot token")
)
func init() { flag.Parse() }
func main() {
s, _ := discordgo.New("Bot " + *BotToken)
s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
fmt.Println("Bot is ready")
})
err := s.Open()
if err != nil {
log.Fatalf("Cannot open the session: %v", err)
}
defer s.Close()
event := createAmazingEvent(s)
transformEventToExternalEvent(s, event)
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
<-stop
log.Println("Graceful shutdown")
}
// Create a new event on guild
func createAmazingEvent(s *discordgo.Session) *discordgo.GuildScheduledEvent {
// Define the starting time (must be in future)
startingTime := time.Now().Add(1 * time.Hour)
// Define the ending time (must be after starting time)
endingTime := startingTime.Add(30 * time.Minute)
// Create the event
scheduledEvent, err := s.GuildScheduledEventCreate(*GuildID, &discordgo.GuildScheduledEventParams{
Name: "Amazing Event",
Description: "This event will start in 1 hour and last 30 minutes",
ScheduledStartTime: &startingTime,
ScheduledEndTime: &endingTime,
EntityType: discordgo.GuildScheduledEventEntityTypeVoice,
ChannelID: *VoiceChannelID,
PrivacyLevel: discordgo.GuildScheduledEventPrivacyLevelGuildOnly,
})
if err != nil {
log.Printf("Error creating scheduled event: %v", err)
return nil
}
fmt.Println("Created scheduled event:", scheduledEvent.Name)
return scheduledEvent
}
func transformEventToExternalEvent(s *discordgo.Session, event *discordgo.GuildScheduledEvent) {
scheduledEvent, err := s.GuildScheduledEventEdit(*GuildID, event.ID, &discordgo.GuildScheduledEventParams{
Name: "Amazing Event @ Discord Website",
EntityType: discordgo.GuildScheduledEventEntityTypeExternal,
EntityMetadata: &discordgo.GuildScheduledEventEntityMetadata{
Location: "https://discord.com",
},
})
if err != nil {
log.Printf("Error during transformation of scheduled voice event into external event: %v", err)
return
}
fmt.Println("Created scheduled event:", scheduledEvent.Name)
}

View file

@ -21,8 +21,9 @@ const timeout time.Duration = time.Second * 10
var games map[string]time.Time = make(map[string]time.Time) var games map[string]time.Time = make(map[string]time.Time)
func init() { flag.Parse() }
func main() { func main() {
flag.Parse()
s, _ := discordgo.New("Bot " + *BotToken) s, _ := discordgo.New("Bot " + *BotToken)
s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) { s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
fmt.Println("Bot is ready") fmt.Println("Bot is ready")

View file

@ -2757,3 +2757,115 @@ func (s *Session) FollowupMessageEdit(appID string, interaction *Interaction, me
func (s *Session) FollowupMessageDelete(appID string, interaction *Interaction, messageID string) error { func (s *Session) FollowupMessageDelete(appID string, interaction *Interaction, messageID string) error {
return s.WebhookMessageDelete(appID, interaction.Token, messageID) return s.WebhookMessageDelete(appID, interaction.Token, messageID)
} }
// ------------------------------------------------------------------------------------------------
// Functions specific to guilds scheduled events
// ------------------------------------------------------------------------------------------------
// GuildScheduledEvents returns an array of GuildScheduledEvent for a guild
// guildID : The ID of a Guild
// userCount : Whether to include the user count in the response
func (s *Session) GuildScheduledEvents(guildID string, userCount bool) (st []*GuildScheduledEvent, err error) {
uri := EndpointGuildScheduledEvents(guildID)
if userCount {
uri += "?with_user_count=true"
}
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildScheduledEvents(guildID))
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// GuildScheduledEvent returns a specific GuildScheduledEvent in a guild
// guildID : The ID of a Guild
// eventID : The ID of the event
// userCount : Whether to include the user count in the response
func (s *Session) GuildScheduledEvent(guildID, eventID string, userCount bool) (st *GuildScheduledEvent, err error) {
uri := EndpointGuildScheduledEvent(guildID, eventID)
if userCount {
uri += "?with_user_count=true"
}
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildScheduledEvent(guildID, eventID))
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// GuildScheduledEventCreate creates a GuildScheduledEvent for a guild and returns it
// guildID : The ID of a Guild
// eventID : The ID of the event
func (s *Session) GuildScheduledEventCreate(guildID string, event *GuildScheduledEventParams) (st *GuildScheduledEvent, err error) {
body, err := s.RequestWithBucketID("POST", EndpointGuildScheduledEvents(guildID), event, EndpointGuildScheduledEvents(guildID))
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// GuildScheduledEventEdit updates a specific event for a guild and returns it.
// guildID : The ID of a Guild
// eventID : The ID of the event
func (s *Session) GuildScheduledEventEdit(guildID, eventID string, event *GuildScheduledEventParams) (st *GuildScheduledEvent, err error) {
body, err := s.RequestWithBucketID("PATCH", EndpointGuildScheduledEvent(guildID, eventID), event, EndpointGuildScheduledEvent(guildID, eventID))
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// GuildScheduledEventDelete deletes a specific GuildScheduledEvent in a guild
// guildID : The ID of a Guild
// eventID : The ID of the event
func (s *Session) GuildScheduledEventDelete(guildID, eventID string) (err error) {
_, err = s.RequestWithBucketID("DELETE", EndpointGuildScheduledEvent(guildID, eventID), nil, EndpointGuildScheduledEvent(guildID, eventID))
return
}
// GuildScheduledEventUsers returns an array of GuildScheduledEventUser for a particular event in a guild
// guildID : The ID of a Guild
// eventID : The ID of the event
// limit : The maximum number of users to return (Max 100)
// withMember : Whether to include the member object in the response
// beforeID : If is not empty all returned users entries will be before the given ID
// afterID : If is not empty all returned users entries will be after the given ID
func (s *Session) GuildScheduledEventUsers(guildID, eventID string, limit int, withMember bool, beforeID, afterID string) (st []*GuildScheduledEventUser, err error) {
uri := EndpointGuildScheduledEventUsers(guildID, eventID)
queryParams := url.Values{}
if withMember {
queryParams.Set("with_member", "true")
}
if limit > 0 {
queryParams.Set("limit", strconv.Itoa(limit))
}
if beforeID != "" {
queryParams.Set("before", beforeID)
}
if afterID != "" {
queryParams.Set("after", afterID)
}
if len(queryParams) > 0 {
uri += "?" + queryParams.Encode()
}
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildScheduledEventUsers(guildID, eventID))
if err != nil {
return
}
err = unmarshal(body, &st)
return
}

View file

@ -767,6 +767,149 @@ type GuildPreview struct {
Description string `json:"description"` Description string `json:"description"`
} }
// GuildScheduledEvent is a representation of a scheduled event in a guild. Only for retrieval of the data.
// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event
type GuildScheduledEvent struct {
// The ID of the scheduled event
ID string `json:"id"`
// The guild id which the scheduled event belongs to
GuildID string `json:"guild_id"`
// The channel id in which the scheduled event will be hosted, or null if scheduled entity type is EXTERNAL
ChannelID string `json:"channel_id"`
// The id of the user that created the scheduled event
CreatorID string `json:"creator_id"`
// The name of the scheduled event (1-100 characters)
Name string `json:"name"`
// The description of the scheduled event (1-1000 characters)
Description string `json:"description"`
// The time the scheduled event will start
ScheduledStartTime time.Time `json:"scheduled_start_time"`
// The time the scheduled event will end, required only when entity_type is EXTERNAL
ScheduledEndTime *time.Time `json:"scheduled_end_time"`
// The privacy level of the scheduled event
PrivacyLevel GuildScheduledEventPrivacyLevel `json:"privacy_level"`
// The status of the scheduled event
Status GuildScheduledEventStatus `json:"status"`
// Type of the entity where event would be hosted
// See field requirements
// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-field-requirements-by-entity-type
EntityType GuildScheduledEventEntityType `json:"entity_type"`
// The id of an entity associated with a guild scheduled event
EntityID string `json:"entity_id"`
// Additional metadata for the guild scheduled event
EntityMetadata GuildScheduledEventEntityMetadata `json:"entity_metadata"`
// The user that created the scheduled event
Creator *User `json:"creator"`
// The number of users subscribed to the scheduled event
UserCount int `json:"user_count"`
// The cover image hash of the scheduled event
// see https://discord.com/developers/docs/reference#image-formatting for more
// information about image formatting
Image string `json:"image"`
}
// GuildScheduledEventParams are the parameters allowed for creating or updating a scheduled event
// https://discord.com/developers/docs/resources/guild-scheduled-event#create-guild-scheduled-event
type GuildScheduledEventParams struct {
// The channel id in which the scheduled event will be hosted, or null if scheduled entity type is EXTERNAL
ChannelID string `json:"channel_id,omitempty"`
// The name of the scheduled event (1-100 characters)
Name string `json:"name,omitempty"`
// The description of the scheduled event (1-1000 characters)
Description string `json:"description,omitempty"`
// The time the scheduled event will start
ScheduledStartTime *time.Time `json:"scheduled_start_time,omitempty"`
// The time the scheduled event will end, required only when entity_type is EXTERNAL
ScheduledEndTime *time.Time `json:"scheduled_end_time,omitempty"`
// The privacy level of the scheduled event
PrivacyLevel GuildScheduledEventPrivacyLevel `json:"privacy_level,omitempty"`
// The status of the scheduled event
Status GuildScheduledEventStatus `json:"status,omitempty"`
// Type of the entity where event would be hosted
// See field requirements
// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-field-requirements-by-entity-type
EntityType GuildScheduledEventEntityType `json:"entity_type,omitempty"`
// Additional metadata for the guild scheduled event
EntityMetadata *GuildScheduledEventEntityMetadata `json:"entity_metadata,omitempty"`
// The cover image hash of the scheduled event
// see https://discord.com/developers/docs/reference#image-formatting for more
// information about image formatting
Image string `json:"image,omitempty"`
}
// MarshalJSON is a helper function to marshal GuildScheduledEventParams
func (p GuildScheduledEventParams) MarshalJSON() ([]byte, error) {
type guildScheduledEventParams GuildScheduledEventParams
if p.EntityType == GuildScheduledEventEntityTypeExternal && p.ChannelID == "" {
return json.Marshal(struct {
guildScheduledEventParams
ChannelID json.RawMessage `json:"channel_id"`
}{
guildScheduledEventParams: guildScheduledEventParams(p),
ChannelID: json.RawMessage("null"),
})
}
return json.Marshal(guildScheduledEventParams(p))
}
// GuildScheduledEventEntityMetadata holds additional metadata for guild scheduled event.
type GuildScheduledEventEntityMetadata struct {
// location of the event (1-100 characters)
// required for events with 'entity_type': EXTERNAL
Location string `json:"location"`
}
// GuildScheduledEventPrivacyLevel is the privacy level of a scheduled event.
// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-privacy-level
type GuildScheduledEventPrivacyLevel int
const (
// GuildScheduledEventPrivacyLevelGuildOnly makes the scheduled
// event is only accessible to guild members
GuildScheduledEventPrivacyLevelGuildOnly GuildScheduledEventPrivacyLevel = 2
)
// GuildScheduledEventStatus is the status of a scheduled event
// Valid Guild Scheduled Event Status Transitions :
// SCHEDULED --> ACTIVE --> COMPLETED
// SCHEDULED --> CANCELED
// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-status
type GuildScheduledEventStatus int
const (
// GuildScheduledEventStatusScheduled represents the current event is in scheduled state
GuildScheduledEventStatusScheduled = 1
// GuildScheduledEventStatusActive represents the current event is in active state
GuildScheduledEventStatusActive = 2
// GuildScheduledEventStatusCompleted represents the current event is in completed state
GuildScheduledEventStatusCompleted = 3
// GuildScheduledEventStatusCanceled represents the current event is in canceled state
GuildScheduledEventStatusCanceled = 4
)
// GuildScheduledEventEntityType is the type of entity associated with a guild scheduled event.
// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-types
type GuildScheduledEventEntityType int
const (
// GuildScheduledEventEntityTypeStageInstance represents a stage channel
GuildScheduledEventEntityTypeStageInstance = 1
// GuildScheduledEventEntityTypeVoice represents a voice channel
GuildScheduledEventEntityTypeVoice = 2
// GuildScheduledEventEntityTypeExternal represents an external event
GuildScheduledEventEntityTypeExternal = 3
)
// GuildScheduledEventUser is a user subscribed to a scheduled event.
// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-user-object
type GuildScheduledEventUser struct {
GuildScheduledEventID string `json:"guild_scheduled_event_id"`
User *User `json:"user"`
Member *Member `json:"member"`
}
// A GuildTemplate represents // A GuildTemplate represents
type GuildTemplate struct { type GuildTemplate struct {
// The unique code for the guild template // The unique code for the guild template
@ -1876,7 +2019,8 @@ const (
IntentDirectMessages | IntentDirectMessages |
IntentDirectMessageReactions | IntentDirectMessageReactions |
IntentDirectMessageTyping | IntentDirectMessageTyping |
IntentGuildScheduledEvents IntentGuildScheduledEvents |
IntentsGuildScheduledEvents
IntentsAll = IntentsAllWithoutPrivileged | IntentsAll = IntentsAllWithoutPrivileged |
IntentGuildMembers | IntentGuildMembers |