api-surface #1
11 changed files with 378 additions and 0 deletions
feat(ergonomics): reply/2, mentions + String.Chars, created_at, format_dt
commit
99208f2212
|
|
@ -30,6 +30,10 @@ defmodule Dexcord.TextChannel do
|
|||
field :default_auto_archive_duration, :integer
|
||||
field :default_thread_rate_limit_per_user, :integer
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.AnnouncementChannel do
|
||||
|
|
@ -45,6 +49,10 @@ defmodule Dexcord.AnnouncementChannel do
|
|||
field :default_auto_archive_duration, :integer
|
||||
field :default_thread_rate_limit_per_user, :integer
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.VoiceChannel do
|
||||
|
|
@ -60,6 +68,10 @@ defmodule Dexcord.VoiceChannel do
|
|||
field :last_message_id, :snowflake
|
||||
field :rate_limit_per_user, :integer
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.StageChannel do
|
||||
|
|
@ -75,6 +87,10 @@ defmodule Dexcord.StageChannel do
|
|||
field :last_message_id, :snowflake
|
||||
field :rate_limit_per_user, :integer
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.CategoryChannel do
|
||||
|
|
@ -84,6 +100,10 @@ defmodule Dexcord.CategoryChannel do
|
|||
discord_struct do
|
||||
include_fields Dexcord.Model.ChannelShared
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.DirectoryChannel do
|
||||
|
|
@ -93,6 +113,10 @@ defmodule Dexcord.DirectoryChannel do
|
|||
discord_struct do
|
||||
include_fields Dexcord.Model.ChannelShared
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.ForumChannel do
|
||||
|
|
@ -111,6 +135,10 @@ defmodule Dexcord.ForumChannel do
|
|||
field :default_sort_order, {:enum, Dexcord.SortOrderType}
|
||||
field :default_forum_layout, {:enum, Dexcord.ForumLayoutType}
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.MediaChannel do
|
||||
|
|
@ -128,6 +156,10 @@ defmodule Dexcord.MediaChannel do
|
|||
field :default_reaction_emoji, {:struct, Dexcord.DefaultReaction}
|
||||
field :default_sort_order, {:enum, Dexcord.SortOrderType}
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.DMChannel do
|
||||
|
|
@ -142,6 +174,10 @@ defmodule Dexcord.DMChannel do
|
|||
field :recipients, {:list, {:struct, Dexcord.User}}, default: []
|
||||
field :last_pin_timestamp, :datetime
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.GroupDMChannel do
|
||||
|
|
@ -161,6 +197,10 @@ defmodule Dexcord.GroupDMChannel do
|
|||
field :application_id, :snowflake
|
||||
field :managed, :boolean
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this channel's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.Thread do
|
||||
|
|
@ -186,6 +226,10 @@ defmodule Dexcord.Thread do
|
|||
field :last_pin_timestamp, :datetime
|
||||
field :newly_created, :boolean, default: false
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this thread's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.UnknownChannel do
|
||||
|
|
@ -254,6 +298,32 @@ defmodule Dexcord.Channel do
|
|||
def from_map(map) when is_map(map), do: Dexcord.UnknownChannel.from_map(map)
|
||||
def from_map(_), do: nil
|
||||
|
||||
@doc """
|
||||
The mention string (`<#id>`) for any channel struct with an integer `id` —
|
||||
guild channels, threads, and DM/group-DM channels alike.
|
||||
"""
|
||||
@spec mention(%{id: Dexcord.Snowflake.t()}) :: String.t()
|
||||
def mention(%{id: id}) when is_integer(id), do: "<##{id}>"
|
||||
|
||||
@doc false
|
||||
def __type_map__, do: @type_map
|
||||
end
|
||||
|
||||
# `String.Chars` for every channel struct: interpolating a channel produces a
|
||||
# real `<#id>` mention (delegating to `Dexcord.Channel.mention/1`).
|
||||
defimpl String.Chars,
|
||||
for: [
|
||||
Dexcord.TextChannel,
|
||||
Dexcord.AnnouncementChannel,
|
||||
Dexcord.VoiceChannel,
|
||||
Dexcord.StageChannel,
|
||||
Dexcord.CategoryChannel,
|
||||
Dexcord.DirectoryChannel,
|
||||
Dexcord.ForumChannel,
|
||||
Dexcord.MediaChannel,
|
||||
Dexcord.DMChannel,
|
||||
Dexcord.GroupDMChannel,
|
||||
Dexcord.Thread
|
||||
] do
|
||||
def to_string(channel), do: Dexcord.Channel.mention(channel)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ defmodule Dexcord.Emoji do
|
|||
field :animated, :boolean, default: false
|
||||
field :available, :boolean
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this emoji's id, or `:error` (unicode/nil id)."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.PartialEmoji do
|
||||
|
|
@ -22,9 +26,27 @@ defmodule Dexcord.PartialEmoji do
|
|||
"""
|
||||
use Dexcord.Struct
|
||||
|
||||
# `to_string/1` below shadows the auto-imported `Kernel.to_string/1`.
|
||||
import Kernel, except: [to_string: 1]
|
||||
|
||||
discord_struct do
|
||||
field :id, :snowflake
|
||||
field :name, :string
|
||||
field :animated, :boolean, default: false
|
||||
end
|
||||
|
||||
@doc """
|
||||
The send-format string for this emoji.
|
||||
|
||||
Custom static: `<:name:id>`; animated: `<a:name:id>`; unicode (nil id): the
|
||||
raw `name` character.
|
||||
"""
|
||||
@spec to_string(t()) :: String.t()
|
||||
def to_string(%{id: nil, name: name}), do: name
|
||||
def to_string(%{id: id, name: name, animated: true}), do: "<a:#{name}:#{id}>"
|
||||
def to_string(%{id: id, name: name}), do: "<:#{name}:#{id}>"
|
||||
end
|
||||
|
||||
defimpl String.Chars, for: Dexcord.PartialEmoji do
|
||||
def to_string(emoji), do: Dexcord.PartialEmoji.to_string(emoji)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ defmodule Dexcord.Guild do
|
|||
field :guild_scheduled_events, {:list, {:struct, Dexcord.GuildScheduledEvent}}, default: []
|
||||
field :soundboard_sounds, {:list, :raw}, default: []
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this guild's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defmodule Dexcord.UnavailableGuild do
|
||||
|
|
|
|||
|
|
@ -34,6 +34,23 @@ defmodule Dexcord.Member do
|
|||
field :user, {:struct, Dexcord.User}
|
||||
include_fields Dexcord.Model.MemberShared
|
||||
end
|
||||
|
||||
@doc "The mention string for this member (`<@id>`), from `user_id` or the nested user."
|
||||
@spec mention(t()) :: String.t()
|
||||
def mention(%{} = member), do: "<@#{member_user_id(member)}>"
|
||||
|
||||
@doc "The creation `DateTime` encoded in this member's user id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{} = member),
|
||||
do: Dexcord.Snowflake.to_datetime(member_user_id(member))
|
||||
|
||||
defp member_user_id(%{user_id: user_id, user: user}) do
|
||||
user_id || (user && user.id)
|
||||
end
|
||||
end
|
||||
|
||||
defimpl String.Chars, for: Dexcord.Member do
|
||||
def to_string(member), do: Dexcord.Member.mention(member)
|
||||
end
|
||||
|
||||
defmodule Dexcord.PartialMember do
|
||||
|
|
|
|||
|
|
@ -44,6 +44,47 @@ defmodule Dexcord.Message do
|
|||
field :call, {:struct, Dexcord.MessageCall}
|
||||
field :shared_client_theme, :raw
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this message's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
|
||||
@doc """
|
||||
Replies to this message. Sets `message_reference` to the source message and
|
||||
routes through `Dexcord.Api.send/2` (so the allowed-mentions config default
|
||||
merge applies).
|
||||
|
||||
`mention_author: true | false` overrides `allowed_mentions.replied_user`
|
||||
(mirroring discord.py) — it is applied AFTER the body is normalized, so it
|
||||
wins over any `replied_user` a caller passed in the body. Everything else
|
||||
behaves like `Dexcord.Api.send/3`.
|
||||
"""
|
||||
@spec reply(t(), term(), keyword()) ::
|
||||
{:ok, t()} | {:error, Dexcord.Api.Error.t()}
|
||||
def reply(msg, body, opts \\ [])
|
||||
|
||||
def reply(%{id: id, channel_id: channel_id}, body, opts) do
|
||||
{mention_author, opts} = Keyword.pop(opts, :mention_author)
|
||||
|
||||
body =
|
||||
body
|
||||
|> Dexcord.Api.Endpoint.encode_body(%{binary_wrap: :content})
|
||||
|> Map.put("message_reference", %{"message_id" => Dexcord.Snowflake.dump(id)})
|
||||
|> apply_mention_author(mention_author)
|
||||
|
||||
Dexcord.Api.send(channel_id, body, opts)
|
||||
end
|
||||
|
||||
defp apply_mention_author(body, nil), do: body
|
||||
|
||||
defp apply_mention_author(body, flag) when is_boolean(flag) do
|
||||
Map.update(
|
||||
body,
|
||||
"allowed_mentions",
|
||||
%{"replied_user" => flag},
|
||||
&Map.put(&1, "replied_user", flag)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Dexcord.MessageReference do
|
||||
|
|
|
|||
|
|
@ -17,6 +17,18 @@ defmodule Dexcord.Role do
|
|||
field :tags, {:struct, Dexcord.RoleTags}
|
||||
field :flags, {:flags, Dexcord.RoleFlags}
|
||||
end
|
||||
|
||||
@doc "The mention string for this role (`<@&id>`)."
|
||||
@spec mention(t()) :: String.t()
|
||||
def mention(%{id: id}), do: "<@&#{id}>"
|
||||
|
||||
@doc "The creation `DateTime` encoded in this role's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defimpl String.Chars, for: Dexcord.Role do
|
||||
def to_string(role), do: Dexcord.Role.mention(role)
|
||||
end
|
||||
|
||||
defmodule Dexcord.RoleColors do
|
||||
|
|
|
|||
|
|
@ -23,6 +23,18 @@ defmodule Dexcord.User do
|
|||
field :collectibles, :raw
|
||||
field :primary_guild, {:struct, Dexcord.PrimaryGuild}
|
||||
end
|
||||
|
||||
@doc "The mention string for this user (`<@id>`)."
|
||||
@spec mention(t()) :: String.t()
|
||||
def mention(%{id: id}), do: "<@#{id}>"
|
||||
|
||||
@doc "The creation `DateTime` encoded in this user's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
||||
defimpl String.Chars, for: Dexcord.User do
|
||||
def to_string(user), do: Dexcord.User.mention(user)
|
||||
end
|
||||
|
||||
defmodule Dexcord.AvatarDecorationData do
|
||||
|
|
|
|||
|
|
@ -16,4 +16,8 @@ defmodule Dexcord.Webhook do
|
|||
field :source_channel, :raw
|
||||
field :url, :string
|
||||
end
|
||||
|
||||
@doc "The creation `DateTime` encoded in this webhook's id, or `:error`."
|
||||
@spec created_at(t()) :: {:ok, DateTime.t()} | :error
|
||||
def created_at(%{id: id}), do: Dexcord.Snowflake.to_datetime(id)
|
||||
end
|
||||
|
|
|
|||
22
lib/dexcord/util.ex
Normal file
22
lib/dexcord/util.ex
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
defmodule Dexcord.Util do
|
||||
@moduledoc "Small formatting helpers for the ergonomics layer."
|
||||
|
||||
# The nine documented Discord timestamp styles (Message Formatting reference):
|
||||
# t short time, T long time, d short date, D long date, f short date/time,
|
||||
# F long date/time, s short relative-ish (seconds), S, R relative.
|
||||
@styles ~w(t T d D f F s S R)
|
||||
|
||||
@doc """
|
||||
Renders a Discord timestamp markdown token `<t:unix[:style]>`.
|
||||
|
||||
Accepts a `DateTime` or a unix-seconds integer. `style` is one of
|
||||
`#{Enum.join(@styles, " ")}` and defaults to `"f"` (per Discord's docs).
|
||||
"""
|
||||
@spec format_dt(DateTime.t() | integer(), String.t()) :: String.t()
|
||||
def format_dt(dt_or_unix, style \\ "f")
|
||||
|
||||
def format_dt(%DateTime{} = dt, style), do: format_dt(DateTime.to_unix(dt), style)
|
||||
|
||||
def format_dt(unix, style) when is_integer(unix) and style in @styles,
|
||||
do: "<t:#{unix}:#{style}>"
|
||||
end
|
||||
131
test/dexcord/ergonomics_helpers_test.exs
Normal file
131
test/dexcord/ergonomics_helpers_test.exs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
defmodule Dexcord.ErgonomicsHelpersTest do
|
||||
@moduledoc """
|
||||
Pure helper tests for the discord.py taste layer (api-surface.AC3.4): mentions,
|
||||
`String.Chars` interpolation, `Dexcord.PartialEmoji.to_string/1`, `created_at/1`,
|
||||
and `Dexcord.Util.format_dt/2`.
|
||||
"""
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias Dexcord.Util
|
||||
|
||||
# Discord's documented example snowflake -> 2016-04-30T11:18:25.796Z.
|
||||
@known_snowflake 175_928_847_299_117_063
|
||||
@known_unix_ms 1_462_015_105_796
|
||||
|
||||
describe "mention/1" do
|
||||
test "User renders <@id>" do
|
||||
assert Dexcord.User.mention(%Dexcord.User{id: 1}) == "<@1>"
|
||||
end
|
||||
|
||||
test "Member renders <@id> from user_id" do
|
||||
assert Dexcord.Member.mention(%Dexcord.Member{user_id: 7}) == "<@7>"
|
||||
end
|
||||
|
||||
test "Member renders <@id> from the nested user when user_id is nil" do
|
||||
assert Dexcord.Member.mention(%Dexcord.Member{user: %Dexcord.User{id: 8}}) == "<@8>"
|
||||
end
|
||||
|
||||
test "Role renders <@&id>" do
|
||||
assert Dexcord.Role.mention(%Dexcord.Role{id: 2}) == "<@&2>"
|
||||
end
|
||||
|
||||
test "Dexcord.Channel.mention/1 renders <#id> for any channel struct" do
|
||||
assert Dexcord.Channel.mention(%Dexcord.TextChannel{id: 3}) == "<#3>"
|
||||
assert Dexcord.Channel.mention(%Dexcord.VoiceChannel{id: 4}) == "<#4>"
|
||||
assert Dexcord.Channel.mention(%Dexcord.Thread{id: 5}) == "<#5>"
|
||||
assert Dexcord.Channel.mention(%Dexcord.DMChannel{id: 6}) == "<#6>"
|
||||
end
|
||||
end
|
||||
|
||||
describe "String.Chars interpolation" do
|
||||
test "a user interpolates as a real ping" do
|
||||
assert "hey #{%Dexcord.User{id: 1}}" == "hey <@1>"
|
||||
end
|
||||
|
||||
test "a member interpolates as a real ping" do
|
||||
assert "#{%Dexcord.Member{user_id: 9}}" == "<@9>"
|
||||
end
|
||||
|
||||
test "a role interpolates as <@&id>" do
|
||||
assert "#{%Dexcord.Role{id: 2}}" == "<@&2>"
|
||||
end
|
||||
|
||||
test "a text channel interpolates as <#id>" do
|
||||
assert "#{%Dexcord.TextChannel{id: 3}}" == "<#3>"
|
||||
end
|
||||
|
||||
test "a thread interpolates as <#id>" do
|
||||
assert "#{%Dexcord.Thread{id: 5}}" == "<#5>"
|
||||
end
|
||||
end
|
||||
|
||||
describe "PartialEmoji.to_string/1" do
|
||||
test "a custom (static) emoji renders <:name:id>" do
|
||||
emoji = %Dexcord.PartialEmoji{id: 100, name: "blob", animated: false}
|
||||
assert Dexcord.PartialEmoji.to_string(emoji) == "<:blob:100>"
|
||||
end
|
||||
|
||||
test "an animated emoji renders <a:name:id>" do
|
||||
emoji = %Dexcord.PartialEmoji{id: 200, name: "party", animated: true}
|
||||
assert Dexcord.PartialEmoji.to_string(emoji) == "<a:party:200>"
|
||||
end
|
||||
|
||||
test "a unicode emoji (nil id) renders its raw name" do
|
||||
emoji = %Dexcord.PartialEmoji{id: nil, name: "🔥"}
|
||||
assert Dexcord.PartialEmoji.to_string(emoji) == "🔥"
|
||||
end
|
||||
|
||||
test "interpolates via String.Chars" do
|
||||
assert "#{%Dexcord.PartialEmoji{id: 100, name: "blob"}}" == "<:blob:100>"
|
||||
assert "#{%Dexcord.PartialEmoji{id: nil, name: "🔥"}}" == "🔥"
|
||||
end
|
||||
end
|
||||
|
||||
describe "Dexcord.Util.format_dt/2" do
|
||||
test "renders every documented style" do
|
||||
for style <- ~w(t T d D f F s S R) do
|
||||
assert Util.format_dt(1_700_000_000, style) == "<t:1700000000:#{style}>"
|
||||
end
|
||||
end
|
||||
|
||||
test "defaults to the f style" do
|
||||
assert Util.format_dt(1_700_000_000) == "<t:1700000000:f>"
|
||||
end
|
||||
|
||||
test "accepts a DateTime and converts to unix" do
|
||||
dt = DateTime.from_unix!(1_700_000_000)
|
||||
assert Util.format_dt(dt) == "<t:1700000000:f>"
|
||||
assert Util.format_dt(dt, "R") == "<t:1700000000:R>"
|
||||
end
|
||||
end
|
||||
|
||||
describe "created_at/1" do
|
||||
test "round-trips a known snowflake vector on a User" do
|
||||
assert {:ok, dt} = Dexcord.User.created_at(%Dexcord.User{id: @known_snowflake})
|
||||
assert DateTime.to_unix(dt, :millisecond) == @known_unix_ms
|
||||
end
|
||||
|
||||
test "works on a Message via its id" do
|
||||
assert {:ok, dt} = Dexcord.Message.created_at(%Dexcord.Message{id: @known_snowflake})
|
||||
assert DateTime.to_unix(dt, :millisecond) == @known_unix_ms
|
||||
end
|
||||
|
||||
test "works on a Member via user_id" do
|
||||
assert {:ok, dt} =
|
||||
Dexcord.Member.created_at(%Dexcord.Member{user_id: @known_snowflake})
|
||||
|
||||
assert DateTime.to_unix(dt, :millisecond) == @known_unix_ms
|
||||
end
|
||||
|
||||
test "works on a guild channel struct" do
|
||||
assert {:ok, dt} =
|
||||
Dexcord.TextChannel.created_at(%Dexcord.TextChannel{id: @known_snowflake})
|
||||
|
||||
assert DateTime.to_unix(dt, :millisecond) == @known_unix_ms
|
||||
end
|
||||
|
||||
test "an emoji with a nil id returns :error" do
|
||||
assert Dexcord.Emoji.created_at(%Dexcord.Emoji{id: nil}) == :error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -98,4 +98,47 @@ defmodule Dexcord.SendTest do
|
|||
refute_receive {:rest_hit, %{path: "/users/@me/channels"}}, 50
|
||||
end
|
||||
end
|
||||
|
||||
describe "AC3.3: Message.reply/2,3 sets message_reference and mention_author" do
|
||||
setup do
|
||||
FakeRest.stub(:post, "/channels/5/messages", FakeRest.resp(200, body: ~s({"id":"1"})))
|
||||
%{msg: %Dexcord.Message{id: 555, channel_id: 5}}
|
||||
end
|
||||
|
||||
test "reply/2 sets message_reference to the source message", %{msg: msg} do
|
||||
assert {:ok, %Dexcord.Message{}} = Dexcord.Message.reply(msg, "pong")
|
||||
|
||||
assert_receive {:rest_hit, %{path: "/channels/5/messages", body: body}}
|
||||
decoded = JSON.decode!(body)
|
||||
|
||||
assert decoded["content"] == "pong"
|
||||
assert decoded["message_reference"] == %{"message_id" => "555"}
|
||||
refute Map.has_key?(decoded, "allowed_mentions")
|
||||
end
|
||||
|
||||
test "mention_author: false sets allowed_mentions.replied_user to false", %{msg: msg} do
|
||||
assert {:ok, %Dexcord.Message{}} = Dexcord.Message.reply(msg, "pong", mention_author: false)
|
||||
|
||||
assert_receive {:rest_hit, %{path: "/channels/5/messages", body: body}}
|
||||
decoded = JSON.decode!(body)
|
||||
|
||||
assert decoded["allowed_mentions"] == %{"replied_user" => false}
|
||||
assert decoded["message_reference"] == %{"message_id" => "555"}
|
||||
end
|
||||
|
||||
test "mention_author: true preserves other allowed_mentions keys and wins over the body",
|
||||
%{msg: msg} do
|
||||
body = %{
|
||||
"content" => "pong",
|
||||
"allowed_mentions" => %{"users" => ["7"], "replied_user" => false}
|
||||
}
|
||||
|
||||
assert {:ok, %Dexcord.Message{}} = Dexcord.Message.reply(msg, body, mention_author: true)
|
||||
|
||||
assert_receive {:rest_hit, %{path: "/channels/5/messages", body: raw}}
|
||||
decoded = JSON.decode!(raw)
|
||||
|
||||
assert decoded["allowed_mentions"] == %{"users" => ["7"], "replied_user" => true}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue