api-surface #1
6 changed files with 729 additions and 0 deletions
feat(events): envelope structs with hydrate slots for all non-full-object events
commit
576bfa1205
50
lib/dexcord/events/channel_events.ex
Normal file
50
lib/dexcord/events/channel_events.ex
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
defmodule Dexcord.Events.ChannelPinsUpdate do
|
||||
@moduledoc "CHANNEL_PINS_UPDATE. https://docs.discord.com/developers/events/gateway-events#channel-pins-update"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :channel_id, :snowflake
|
||||
field :last_pin_timestamp, :datetime, tristate: true
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.ThreadDelete do
|
||||
@moduledoc "THREAD_DELETE. https://docs.discord.com/developers/events/gateway-events#thread-delete"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :parent_id, :snowflake
|
||||
field :type, {:enum, Dexcord.ChannelType}
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.ThreadListSync do
|
||||
@moduledoc "THREAD_LIST_SYNC. https://docs.discord.com/developers/events/gateway-events#thread-list-sync"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :channel_ids, {:list, :snowflake}, default: []
|
||||
field :threads, {:list, {:struct, Dexcord.Channel}}, default: []
|
||||
field :members, {:list, {:struct, Dexcord.ThreadMember}}, default: []
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.ThreadMembersUpdate do
|
||||
@moduledoc "THREAD_MEMBERS_UPDATE. https://docs.discord.com/developers/events/gateway-events#thread-members-update"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :member_count, :integer
|
||||
field :added_members, {:list, {:struct, Dexcord.ThreadMember}}, default: []
|
||||
field :removed_member_ids, {:list, :snowflake}, default: []
|
||||
end
|
||||
end
|
||||
166
lib/dexcord/events/guild_events.ex
Normal file
166
lib/dexcord/events/guild_events.ex
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
defmodule Dexcord.Events.GuildBanAdd do
|
||||
@moduledoc "GUILD_BAN_ADD. https://docs.discord.com/developers/events/gateway-events#guild-ban-add"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :user, {:struct, Dexcord.User}
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildBanRemove do
|
||||
@moduledoc "GUILD_BAN_REMOVE. https://docs.discord.com/developers/events/gateway-events#guild-ban-remove"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :user, {:struct, Dexcord.User}
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildEmojisUpdate do
|
||||
@moduledoc "GUILD_EMOJIS_UPDATE. https://docs.discord.com/developers/events/gateway-events#guild-emojis-update"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :emojis, {:list, {:struct, Dexcord.Emoji}}, default: []
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildStickersUpdate do
|
||||
@moduledoc "GUILD_STICKERS_UPDATE. https://docs.discord.com/developers/events/gateway-events#guild-stickers-update"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :stickers, {:list, {:struct, Dexcord.Sticker}}, default: []
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildIntegrationsUpdate do
|
||||
@moduledoc "GUILD_INTEGRATIONS_UPDATE. https://docs.discord.com/developers/events/gateway-events#guild-integrations-update"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildMemberRemove do
|
||||
@moduledoc "GUILD_MEMBER_REMOVE. https://docs.discord.com/developers/events/gateway-events#guild-member-remove"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :user, {:struct, Dexcord.User}
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildMemberUpdate do
|
||||
@moduledoc """
|
||||
GUILD_MEMBER_UPDATE.
|
||||
|
||||
This is NOT a `Dexcord.Member`: `joined_at` is nullable, there is no `flags`,
|
||||
and several fields carry PATCH tristate semantics for the Phase 6 cache merge
|
||||
(`:absent` means the key was not sent, distinct from an explicit `null`).
|
||||
|
||||
https://docs.discord.com/developers/events/gateway-events#guild-member-update
|
||||
"""
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :roles, {:list, :snowflake}, default: []
|
||||
field :user, {:struct, Dexcord.User}
|
||||
field :nick, :string, tristate: true
|
||||
field :avatar, :string
|
||||
field :banner, :string
|
||||
field :joined_at, :datetime
|
||||
field :premium_since, :datetime, tristate: true
|
||||
field :deaf, :boolean
|
||||
field :mute, :boolean
|
||||
field :pending, :boolean
|
||||
field :communication_disabled_until, :datetime, tristate: true
|
||||
field :avatar_decoration_data, :raw, tristate: true
|
||||
field :collectibles, :raw, tristate: true
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildMembersChunk do
|
||||
@moduledoc "GUILD_MEMBERS_CHUNK. https://docs.discord.com/developers/events/gateway-events#guild-members-chunk"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :members, {:list, {:struct, Dexcord.Member}}, default: []
|
||||
field :chunk_index, :integer
|
||||
field :chunk_count, :integer
|
||||
field :not_found, {:list, :raw}, default: []
|
||||
field :presences, {:list, {:struct, Dexcord.Presence}}, default: []
|
||||
field :nonce, :string
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildRoleCreate do
|
||||
@moduledoc "GUILD_ROLE_CREATE. https://docs.discord.com/developers/events/gateway-events#guild-role-create"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :role, {:struct, Dexcord.Role}
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildRoleUpdate do
|
||||
@moduledoc "GUILD_ROLE_UPDATE. https://docs.discord.com/developers/events/gateway-events#guild-role-update"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :role, {:struct, Dexcord.Role}
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildRoleDelete do
|
||||
@moduledoc "GUILD_ROLE_DELETE. https://docs.discord.com/developers/events/gateway-events#guild-role-delete"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :role_id, :snowflake
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildScheduledEventUserAdd do
|
||||
@moduledoc "GUILD_SCHEDULED_EVENT_USER_ADD. https://docs.discord.com/developers/events/gateway-events#guild-scheduled-event-user-add"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_scheduled_event_id, :snowflake
|
||||
field :user_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
hydrate :user, from: :user_id, type: Dexcord.User
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.GuildScheduledEventUserRemove do
|
||||
@moduledoc "GUILD_SCHEDULED_EVENT_USER_REMOVE. https://docs.discord.com/developers/events/gateway-events#guild-scheduled-event-user-remove"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_scheduled_event_id, :snowflake
|
||||
field :user_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
hydrate :user, from: :user_id, type: Dexcord.User
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
123
lib/dexcord/events/message_events.ex
Normal file
123
lib/dexcord/events/message_events.ex
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
defmodule Dexcord.Events.MessageDelete do
|
||||
@moduledoc "MESSAGE_DELETE. https://docs.discord.com/developers/events/gateway-events#message-delete"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :id, :snowflake
|
||||
field :channel_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.MessageDeleteBulk do
|
||||
@moduledoc "MESSAGE_DELETE_BULK. https://docs.discord.com/developers/events/gateway-events#message-delete-bulk"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :ids, {:list, :snowflake}, default: []
|
||||
field :channel_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.ReactionAdd do
|
||||
@moduledoc "MESSAGE_REACTION_ADD. https://docs.discord.com/developers/events/gateway-events#message-reaction-add"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :user_id, :snowflake
|
||||
field :channel_id, :snowflake
|
||||
field :message_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :member, {:struct, Dexcord.Member}
|
||||
field :emoji, {:struct, Dexcord.PartialEmoji}
|
||||
field :message_author_id, :snowflake
|
||||
field :burst, :boolean
|
||||
field :burst_colors, {:list, :string}, default: []
|
||||
field :type, {:enum, Dexcord.ReactionType}
|
||||
hydrate :user, from: :user_id, type: Dexcord.User
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.ReactionRemove do
|
||||
@moduledoc "MESSAGE_REACTION_REMOVE. https://docs.discord.com/developers/events/gateway-events#message-reaction-remove"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :user_id, :snowflake
|
||||
field :channel_id, :snowflake
|
||||
field :message_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :emoji, {:struct, Dexcord.PartialEmoji}
|
||||
field :burst, :boolean
|
||||
field :type, {:enum, Dexcord.ReactionType}
|
||||
hydrate :user, from: :user_id, type: Dexcord.User
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.ReactionRemoveAll do
|
||||
@moduledoc "MESSAGE_REACTION_REMOVE_ALL. https://docs.discord.com/developers/events/gateway-events#message-reaction-remove-all"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :channel_id, :snowflake
|
||||
field :message_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.ReactionRemoveEmoji do
|
||||
@moduledoc "MESSAGE_REACTION_REMOVE_EMOJI. https://docs.discord.com/developers/events/gateway-events#message-reaction-remove-emoji"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :channel_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :message_id, :snowflake
|
||||
field :emoji, {:struct, Dexcord.PartialEmoji}
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.PollVoteAdd do
|
||||
@moduledoc "MESSAGE_POLL_VOTE_ADD. https://docs.discord.com/developers/events/gateway-events#message-poll-vote-add"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :user_id, :snowflake
|
||||
field :channel_id, :snowflake
|
||||
field :message_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :answer_id, :integer
|
||||
hydrate :user, from: :user_id, type: Dexcord.User
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.PollVoteRemove do
|
||||
@moduledoc "MESSAGE_POLL_VOTE_REMOVE. https://docs.discord.com/developers/events/gateway-events#message-poll-vote-remove"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :user_id, :snowflake
|
||||
field :channel_id, :snowflake
|
||||
field :message_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :answer_id, :integer
|
||||
hydrate :user, from: :user_id, type: Dexcord.User
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
124
lib/dexcord/events/misc_events.ex
Normal file
124
lib/dexcord/events/misc_events.ex
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
defmodule Dexcord.Events.AutoModerationActionExecution do
|
||||
@moduledoc "AUTO_MODERATION_ACTION_EXECUTION. https://docs.discord.com/developers/events/gateway-events#auto-moderation-action-execution"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :action, {:struct, Dexcord.AutoModerationAction}
|
||||
field :rule_id, :snowflake
|
||||
field :rule_trigger_type, {:enum, Dexcord.AutoModerationTriggerType}
|
||||
field :user_id, :snowflake
|
||||
field :channel_id, :snowflake
|
||||
field :message_id, :snowflake
|
||||
field :alert_system_message_id, :snowflake
|
||||
field :content, :string
|
||||
field :matched_keyword, :string
|
||||
field :matched_content, :string
|
||||
hydrate :user, from: :user_id, type: Dexcord.User
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.IntegrationDelete do
|
||||
@moduledoc "INTEGRATION_DELETE. https://docs.discord.com/developers/events/gateway-events#integration-delete"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :application_id, :snowflake
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.InviteCreate do
|
||||
@moduledoc "INVITE_CREATE. https://docs.discord.com/developers/events/gateway-events#invite-create"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :channel_id, :snowflake
|
||||
field :code, :string
|
||||
field :created_at, :datetime
|
||||
field :guild_id, :snowflake
|
||||
field :inviter, {:struct, Dexcord.User}
|
||||
field :max_age, :integer
|
||||
field :max_uses, :integer
|
||||
field :target_type, {:enum, Dexcord.InviteTargetType}
|
||||
field :target_user, {:struct, Dexcord.User}
|
||||
field :target_application, :raw
|
||||
field :temporary, :boolean
|
||||
field :uses, :integer
|
||||
field :expires_at, :datetime
|
||||
field :role_ids, {:list, :snowflake}, default: []
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.InviteDelete do
|
||||
@moduledoc "INVITE_DELETE. https://docs.discord.com/developers/events/gateway-events#invite-delete"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :channel_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :code, :string
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.TypingStart do
|
||||
@moduledoc "TYPING_START. `timestamp` is unix SECONDS (integer), NOT a datetime. https://docs.discord.com/developers/events/gateway-events#typing-start"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :channel_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :user_id, :snowflake
|
||||
field :timestamp, :integer
|
||||
field :member, {:struct, Dexcord.Member}
|
||||
hydrate :user, from: :user_id, type: Dexcord.User
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.VoiceChannelEffectSend do
|
||||
@moduledoc "VOICE_CHANNEL_EFFECT_SEND. https://docs.discord.com/developers/events/gateway-events#voice-channel-effect-send"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :channel_id, :snowflake
|
||||
field :guild_id, :snowflake
|
||||
field :user_id, :snowflake
|
||||
field :emoji, :raw
|
||||
field :animation_type, {:enum, Dexcord.VoiceAnimationType}
|
||||
field :animation_id, :integer
|
||||
field :sound_id, :raw
|
||||
field :sound_volume, :number
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.VoiceServerUpdate do
|
||||
@moduledoc "VOICE_SERVER_UPDATE. A null `endpoint` means the server was lost; await reallocation. https://docs.discord.com/developers/events/gateway-events#voice-server-update"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :token, :string
|
||||
field :guild_id, :snowflake
|
||||
field :endpoint, :string
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.Events.WebhooksUpdate do
|
||||
@moduledoc "WEBHOOKS_UPDATE. https://docs.discord.com/developers/events/gateway-events#webhooks-update"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :guild_id, :snowflake
|
||||
field :channel_id, :snowflake
|
||||
hydrate :channel, from: :channel_id, type: :channel
|
||||
hydrate :guild, from: :guild_id, type: Dexcord.Guild
|
||||
end
|
||||
end
|
||||
14
lib/dexcord/events/ready.ex
Normal file
14
lib/dexcord/events/ready.ex
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
defmodule Dexcord.Events.Ready do
|
||||
@moduledoc "The READY dispatch payload. https://docs.discord.com/developers/events/gateway-events#ready"
|
||||
use Dexcord.Struct
|
||||
|
||||
discord_struct do
|
||||
field :v, :integer
|
||||
field :user, {:struct, Dexcord.User}
|
||||
field :guilds, {:list, {:struct, Dexcord.UnavailableGuild}}, default: []
|
||||
field :session_id, :string
|
||||
field :resume_gateway_url, :string
|
||||
field :shard, {:list, :integer}
|
||||
field :application, :raw
|
||||
end
|
||||
end
|
||||
252
test/dexcord/events_envelope_test.exs
Normal file
252
test/dexcord/events_envelope_test.exs
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
defmodule Dexcord.EventsEnvelopeTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias Dexcord.Events
|
||||
|
||||
describe "message_events.ex" do
|
||||
test "ReactionAdd decodes member, unicode emoji, burst; hydrate slots default nil" do
|
||||
raw = %{
|
||||
"user_id" => "111",
|
||||
"channel_id" => "222",
|
||||
"message_id" => "333",
|
||||
"guild_id" => "444",
|
||||
"member" => %{"nick" => "bee", "user" => %{"id" => "111", "username" => "bee"}},
|
||||
"emoji" => %{"id" => nil, "name" => "🔥"},
|
||||
"message_author_id" => "555",
|
||||
"burst" => true,
|
||||
"burst_colors" => ["#ffffff"],
|
||||
"type" => 0
|
||||
}
|
||||
|
||||
assert %Events.ReactionAdd{} = ev = Events.ReactionAdd.from_map(raw)
|
||||
assert ev.user_id == 111
|
||||
assert ev.channel_id == 222
|
||||
assert ev.message_id == 333
|
||||
assert ev.guild_id == 444
|
||||
assert %Dexcord.Member{nick: "bee"} = ev.member
|
||||
assert %Dexcord.User{username: "bee"} = ev.member.user
|
||||
assert %Dexcord.PartialEmoji{name: "🔥", id: nil} = ev.emoji
|
||||
assert ev.message_author_id == 555
|
||||
assert ev.burst == true
|
||||
assert ev.burst_colors == ["#ffffff"]
|
||||
assert ev.type == :normal
|
||||
|
||||
# hydrate slots exist, default to nil, and are declared
|
||||
assert ev.user == nil
|
||||
assert ev.channel == nil
|
||||
assert ev.guild == nil
|
||||
|
||||
slots = Enum.map(Events.ReactionAdd.__hydrations__(), & &1.name)
|
||||
assert :user in slots
|
||||
assert :channel in slots
|
||||
assert :guild in slots
|
||||
end
|
||||
|
||||
test "MessageDelete decodes minimal payload with hydrate slots" do
|
||||
ev = Events.MessageDelete.from_map(%{"id" => "1", "channel_id" => "2", "guild_id" => "3"})
|
||||
assert %Events.MessageDelete{id: 1, channel_id: 2, guild_id: 3} = ev
|
||||
assert ev.channel == nil
|
||||
assert ev.guild == nil
|
||||
end
|
||||
|
||||
test "MessageDeleteBulk decodes ids list" do
|
||||
ev = Events.MessageDeleteBulk.from_map(%{"ids" => ["1", "2"], "channel_id" => "9"})
|
||||
assert ev.ids == [1, 2]
|
||||
assert ev.channel_id == 9
|
||||
end
|
||||
|
||||
test "PollVoteAdd decodes answer_id" do
|
||||
ev =
|
||||
Events.PollVoteAdd.from_map(%{
|
||||
"user_id" => "1",
|
||||
"channel_id" => "2",
|
||||
"message_id" => "3",
|
||||
"guild_id" => "4",
|
||||
"answer_id" => 7
|
||||
})
|
||||
|
||||
assert ev.answer_id == 7
|
||||
assert ev.user == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "guild_events.ex" do
|
||||
test "GuildMemberUpdate: nick present-null -> nil, absent premium_since -> :absent" do
|
||||
raw = %{
|
||||
"guild_id" => "1",
|
||||
"roles" => ["10", "11"],
|
||||
"user" => %{"id" => "2", "username" => "x"},
|
||||
"nick" => nil,
|
||||
"joined_at" => "2021-01-01T00:00:00.000000+00:00"
|
||||
}
|
||||
|
||||
ev = Events.GuildMemberUpdate.from_map(raw)
|
||||
assert ev.guild_id == 1
|
||||
assert ev.roles == [10, 11]
|
||||
assert %Dexcord.User{username: "x"} = ev.user
|
||||
assert ev.nick == nil
|
||||
assert ev.premium_since == :absent
|
||||
assert ev.communication_disabled_until == :absent
|
||||
end
|
||||
|
||||
test "GuildRoleCreate decodes nested role + guild hydrate" do
|
||||
ev =
|
||||
Events.GuildRoleCreate.from_map(%{
|
||||
"guild_id" => "1",
|
||||
"role" => %{"id" => "5", "name" => "admin"}
|
||||
})
|
||||
|
||||
assert ev.guild_id == 1
|
||||
assert %Dexcord.Role{name: "admin"} = ev.role
|
||||
assert ev.guild == nil
|
||||
end
|
||||
|
||||
test "GuildRoleDelete decodes role_id" do
|
||||
ev = Events.GuildRoleDelete.from_map(%{"guild_id" => "1", "role_id" => "5"})
|
||||
assert ev.role_id == 5
|
||||
end
|
||||
|
||||
test "GuildMembersChunk decodes nested members" do
|
||||
ev =
|
||||
Events.GuildMembersChunk.from_map(%{
|
||||
"guild_id" => "1",
|
||||
"members" => [%{"user" => %{"id" => "2"}}],
|
||||
"chunk_index" => 0,
|
||||
"chunk_count" => 1
|
||||
})
|
||||
|
||||
assert [%Dexcord.Member{}] = ev.members
|
||||
assert ev.chunk_index == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "channel_events.ex" do
|
||||
test "ThreadMembersUpdate: added_members with nested member" do
|
||||
raw = %{
|
||||
"id" => "1",
|
||||
"guild_id" => "2",
|
||||
"member_count" => 3,
|
||||
"added_members" => [
|
||||
%{"id" => "1", "user_id" => "9", "member" => %{"user" => %{"id" => "9"}}}
|
||||
],
|
||||
"removed_member_ids" => ["8"]
|
||||
}
|
||||
|
||||
ev = Events.ThreadMembersUpdate.from_map(raw)
|
||||
assert ev.member_count == 3
|
||||
assert [%Dexcord.ThreadMember{} = tm] = ev.added_members
|
||||
assert %Dexcord.Member{} = tm.member
|
||||
assert ev.removed_member_ids == [8]
|
||||
end
|
||||
|
||||
test "ChannelPinsUpdate tristate last_pin_timestamp absent -> :absent" do
|
||||
ev = Events.ChannelPinsUpdate.from_map(%{"guild_id" => "1", "channel_id" => "2"})
|
||||
assert ev.last_pin_timestamp == :absent
|
||||
assert ev.channel == nil
|
||||
end
|
||||
|
||||
test "ThreadDelete decodes type enum" do
|
||||
ev =
|
||||
Events.ThreadDelete.from_map(%{
|
||||
"id" => "1",
|
||||
"guild_id" => "2",
|
||||
"parent_id" => "3",
|
||||
"type" => 11
|
||||
})
|
||||
|
||||
assert ev.id == 1
|
||||
assert ev.type == :public_thread
|
||||
end
|
||||
end
|
||||
|
||||
describe "misc_events.ex" do
|
||||
test "TypingStart: integer timestamp stays integer" do
|
||||
raw = %{
|
||||
"channel_id" => "1",
|
||||
"guild_id" => "2",
|
||||
"user_id" => "3",
|
||||
"timestamp" => 1_700_000_000,
|
||||
"member" => %{"user" => %{"id" => "3"}}
|
||||
}
|
||||
|
||||
ev = Events.TypingStart.from_map(raw)
|
||||
assert ev.timestamp == 1_700_000_000
|
||||
assert is_integer(ev.timestamp)
|
||||
assert %Dexcord.Member{} = ev.member
|
||||
assert ev.user == nil
|
||||
end
|
||||
|
||||
test "InviteCreate: expires_at null stays nil" do
|
||||
raw = %{
|
||||
"channel_id" => "1",
|
||||
"code" => "abc",
|
||||
"created_at" => "2021-01-01T00:00:00.000000+00:00",
|
||||
"guild_id" => "2",
|
||||
"max_age" => 3600,
|
||||
"max_uses" => 0,
|
||||
"temporary" => false,
|
||||
"uses" => 0,
|
||||
"expires_at" => nil
|
||||
}
|
||||
|
||||
ev = Events.InviteCreate.from_map(raw)
|
||||
assert ev.code == "abc"
|
||||
assert ev.expires_at == nil
|
||||
assert ev.channel == nil
|
||||
end
|
||||
|
||||
test "VoiceServerUpdate decodes token/endpoint" do
|
||||
ev =
|
||||
Events.VoiceServerUpdate.from_map(%{
|
||||
"token" => "t",
|
||||
"guild_id" => "1",
|
||||
"endpoint" => "smart.example"
|
||||
})
|
||||
|
||||
assert ev.token == "t"
|
||||
assert ev.endpoint == "smart.example"
|
||||
end
|
||||
|
||||
test "AutoModerationActionExecution decodes nested action + enum" do
|
||||
ev =
|
||||
Events.AutoModerationActionExecution.from_map(%{
|
||||
"guild_id" => "1",
|
||||
"action" => %{"type" => 1, "metadata" => %{"channel_id" => "9"}},
|
||||
"rule_id" => "2",
|
||||
"rule_trigger_type" => 1,
|
||||
"user_id" => "3",
|
||||
"content" => "bad word"
|
||||
})
|
||||
|
||||
assert %Dexcord.AutoModerationAction{type: :block_message} = ev.action
|
||||
assert ev.rule_trigger_type == :keyword
|
||||
assert ev.content == "bad word"
|
||||
end
|
||||
|
||||
test "WebhooksUpdate decodes with channel/guild hydrates" do
|
||||
ev = Events.WebhooksUpdate.from_map(%{"guild_id" => "1", "channel_id" => "2"})
|
||||
assert ev.guild_id == 1
|
||||
assert ev.channel_id == 2
|
||||
assert ev.channel == nil
|
||||
assert ev.guild == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "ready.ex" do
|
||||
test "Ready decodes user + unavailable guilds" do
|
||||
ev =
|
||||
Events.Ready.from_map(%{
|
||||
"v" => 10,
|
||||
"user" => %{"id" => "1", "username" => "bot"},
|
||||
"guilds" => [%{"id" => "9", "unavailable" => true}],
|
||||
"session_id" => "sess",
|
||||
"resume_gateway_url" => "wss://example"
|
||||
})
|
||||
|
||||
assert ev.v == 10
|
||||
assert %Dexcord.User{username: "bot"} = ev.user
|
||||
assert [%Dexcord.UnavailableGuild{id: 9, unavailable: true}] = ev.guilds
|
||||
assert ev.session_id == "sess"
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue