api-surface #1

Merged
luna merged 51 commits from api-surface into mistress 2026-07-05 14:43:13 +00:00
3 changed files with 144 additions and 0 deletions
Showing only changes of commit 0c22758260 - Show all commits

feat(model): Role, RoleColors, RoleTags (presence booleans), Overwrite

Luna 2026-07-05 03:54:56 -03:00

View file

@ -0,0 +1,11 @@
defmodule Dexcord.Overwrite do
@moduledoc "A channel permission overwrite."
use Dexcord.Struct
discord_struct do
field :id, :snowflake
field :type, {:enum, Dexcord.OverwriteType}
field :allow, {:flags, Dexcord.Permissions}, wire_string: true
field :deny, {:flags, Dexcord.Permissions}, wire_string: true
end
end

49
lib/dexcord/model/role.ex Normal file
View file

@ -0,0 +1,49 @@
defmodule Dexcord.Role do
@moduledoc "A guild role. https://docs.discord.com/developers/topics/permissions"
use Dexcord.Struct
discord_struct do
field :id, :snowflake
field :name, :string
field :color, :integer
field :colors, {:struct, Dexcord.RoleColors}
field :hoist, :boolean
field :icon, :string
field :unicode_emoji, :string
field :position, :integer
field :permissions, {:flags, Dexcord.Permissions}, wire_string: true
field :managed, :boolean
field :mentionable, :boolean
field :tags, {:struct, Dexcord.RoleTags}
field :flags, {:flags, Dexcord.RoleFlags}
end
end
defmodule Dexcord.RoleColors do
@moduledoc false
use Dexcord.Struct
discord_struct do
field :primary_color, :integer
field :secondary_color, :integer
field :tertiary_color, :integer
end
end
defmodule Dexcord.RoleTags do
@moduledoc """
Role tags. Docs: "Tags with type null represent booleans. They will be
present and set to null if they are 'true', and will be not present if
they are 'false'." — the three `:presence` fields below.
"""
use Dexcord.Struct
discord_struct do
field :bot_id, :snowflake
field :integration_id, :snowflake
field :premium_subscriber, :presence
field :subscription_listing_id, :snowflake
field :available_for_purchase, :presence
field :guild_connections, :presence
end
end

View file

@ -0,0 +1,84 @@
defmodule Dexcord.ModelRoleTest do
use ExUnit.Case, async: true
describe "Role.from_map/1 — RoleTags presence booleans (api-surface.AC2.7)" do
test "premium_subscriber present-null is true, absent tag is false" do
map = %{
"id" => "1",
"name" => "Booster",
"permissions" => "0",
"tags" => %{"bot_id" => "2", "premium_subscriber" => nil}
}
role = Dexcord.Role.from_map(map)
assert %Dexcord.RoleTags{} = role.tags
assert role.tags.premium_subscriber == true
assert role.tags.available_for_purchase == false
assert role.tags.guild_connections == false
assert role.tags.bot_id == 2
end
end
describe "Role.from_map/1 — string permission bitfields (wire_string)" do
test "a >2^31 permission string decodes to an integer" do
role = Dexcord.Role.from_map(%{"id" => "1", "name" => "r", "permissions" => "2147483648"})
assert role.permissions == 2_147_483_648
end
test "permission bits are queryable after decode" do
role = Dexcord.Role.from_map(%{"id" => "1", "name" => "r", "permissions" => "8"})
assert Dexcord.Permissions.has?(role.permissions, :administrator)
end
end
describe "Role.to_map/1" do
test "re-encodes permissions as a decimal string and premium_subscriber as present-null" do
map = %{
"id" => "1",
"name" => "Booster",
"permissions" => "8",
"tags" => %{"premium_subscriber" => nil}
}
out = map |> Dexcord.Role.from_map() |> Dexcord.Role.to_map()
assert out["permissions"] == "8"
assert Map.has_key?(out["tags"], "premium_subscriber")
assert out["tags"]["premium_subscriber"] == nil
end
end
describe "Role colors" do
test "colors struct decodes nested" do
map = %{
"id" => "1",
"name" => "r",
"colors" => %{"primary_color" => 1, "secondary_color" => 2, "tertiary_color" => 3}
}
role = Dexcord.Role.from_map(map)
assert %Dexcord.RoleColors{} = role.colors
assert role.colors.primary_color == 1
assert role.colors.secondary_color == 2
assert role.colors.tertiary_color == 3
end
end
describe "Overwrite" do
test "allow/deny round-trip as decimal strings" do
map = %{"id" => "1", "type" => 0, "allow" => "1024", "deny" => "0"}
ow = Dexcord.Overwrite.from_map(map)
assert ow.id == 1
assert ow.type == :role
assert ow.allow == 1024
assert ow.deny == 0
out = Dexcord.Overwrite.to_map(ow)
assert out["allow"] == "1024"
assert out["deny"] == "0"
assert out["type"] == 0
end
end
end