Skip to content

Commit

Permalink
Merge pull request #585 from Kraigie/jb3/guild-attributes
Browse files Browse the repository at this point in the history
Add new guild attributes
  • Loading branch information
jchristgit authored May 7, 2024
2 parents e07393f + acd150f commit 45c892e
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 5 deletions.
4 changes: 4 additions & 0 deletions lib/nostrum/constants.ex
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ defmodule Nostrum.Constants do
def cdn_emoji(id, image_format), do: "/emojis/#{id}.#{image_format}"
def cdn_icon(id, icon, image_format), do: "/icons/#{id}/#{icon}.#{image_format}"
def cdn_splash(id, splash, image_format), do: "/splashes/#{id}/#{splash}.#{image_format}"
def cdn_guild_banner(id, banner, image_format), do: "/banners/#{id}/#{banner}.#{image_format}"

def cdn_discovery_splash(id, splash, image_format),
do: "/discovery-splashes/#{id}/#{splash}.#{image_format}"

def cdn_guild_avatar(guild_id, user_id, avatar_hash, image_format) do
"/guilds/#{guild_id}/users/#{user_id}/avatars/#{avatar_hash}.#{image_format}"
Expand Down
201 changes: 196 additions & 5 deletions lib/nostrum/struct/guild.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ defmodule Nostrum.Struct.Guild do
:system_channel_id,
:rules_channel_id,
:public_updates_channel_id,
:safety_alerts_channel_id,
:joined_at,
:large,
:unavailable,
Expand All @@ -50,7 +51,21 @@ defmodule Nostrum.Struct.Guild do
:guild_scheduled_events,
:vanity_url_code,
:threads,
:stickers
:stickers,
:discovery_splash,
:system_channel_flags,
:max_presences,
:max_members,
:description,
:banner,
:premium_tier,
:premium_subscription_count,
:preferred_locale,
:max_video_channel_users,
:max_stage_video_channel_users,
:welcome_screen,
:nsfw_level,
:premium_progress_bar_enabled
]

@typedoc "The guild's id"
Expand Down Expand Up @@ -165,6 +180,63 @@ defmodule Nostrum.Struct.Guild do
@typedoc "Custom stickers registered to the guild"
@type stickers :: [Sticker.t()]

@typedoc "Hash of the Discovery splash screen"
@type discovery_splash :: String.t() | nil

@typedoc """
Bitset representing the system channel flags
See `Nostrum.Struct.Guild.SystemChannelFlags` for more information on the flag
contents as well as methods to parse and create your own values for this
field.
"""
@type system_channel_flags :: pos_integer()

@typedoc """
Maximum number of presences for the guild.
This will be unset for most guilds, except for in Discord's terms, the
"largest of guilds", where the field will be set to the maximum number of
online (gateway connected) members.
"""
@type max_presences :: pos_integer() | nil

@typedoc "Maximum members for the guild"
@type max_members :: pos_integer() | nil

@typedoc "User-set description of the guild"
@type description :: String.t() | nil

@typedoc "Banner hash for the guild, if prefixed with `a_` an animated GIF is available."
@type banner :: String.t() | nil

@typedoc "Premium tier of the guild (0-3)"
@type premium_tier :: 0..3

@typedoc "Number of boosts received by the guild"
@type premium_subscription_count :: pos_integer()

@typedoc "Preferred locale for the guild, set by the user"
@type preferred_locale :: String.t() | nil

@typedoc "The maximum amount of users in a video channel"
@type max_video_channel_users :: pos_integer() | nil

@typedoc "The maximum amount of users in a stage video channel"
@type max_stage_video_channel_users :: pos_integer() | nil

@typedoc "The welcome screen of a Community guild, shown to new members, returned in an Invite's guild object"
@type welcome_screen :: map() | nil

@typedoc "NSFW level for the guild, unrated guilds have `:default`"
@type nsfw_level :: :default | :explicit | :safe | :age_restricted

@typedoc "Whether the guild has the boost progress bar enabled"
@type premium_progress_bar_enabled :: boolean

@typedoc "The id of the channel where admins and moderators of Community guilds receive safety alerts from Discord"
@type safety_alerts_channel_id :: Channel.id() | nil

@typedoc """
A `Nostrum.Struct.Guild` that is sent on user-specific rest endpoints.
"""
Expand Down Expand Up @@ -198,7 +270,22 @@ defmodule Nostrum.Struct.Guild do
channels: nil,
vanity_url_code: nil,
threads: nil,
stickers: nil
stickers: nil,
discovery_splash: nil,
system_channel_flags: nil,
max_presences: nil,
max_members: nil,
description: nil,
banner: nil,
premium_tier: nil,
premium_subscription_count: nil,
preferred_locale: nil,
max_video_channel_users: nil,
max_stage_video_channel_users: nil,
welcome_screen: nil,
nsfw_level: nil,
premium_progress_bar_enabled: nil,
safety_alerts_channel_id: nil
}

@typedoc """
Expand Down Expand Up @@ -235,7 +322,22 @@ defmodule Nostrum.Struct.Guild do
voice_states: nil,
channels: nil,
guild_scheduled_events: nil,
threads: nil
threads: nil,
discovery_splash: nil,
system_channel_flags: nil,
max_presences: nil,
max_members: nil,
description: nil,
banner: nil,
premium_tier: nil,
premium_subscription_count: nil,
preferred_locale: nil,
max_video_channel_users: nil,
max_stage_video_channel_users: nil,
welcome_screen: nil,
nsfw_level: nil,
premium_progress_bar_enabled: nil,
safety_alerts_channel_id: nil
}

@typedoc """
Expand Down Expand Up @@ -272,7 +374,22 @@ defmodule Nostrum.Struct.Guild do
guild_scheduled_events: nil,
vanity_url_code: nil,
threads: nil,
stickers: nil
stickers: nil,
discovery_splash: nil,
system_channel_flags: nil,
max_presences: nil,
max_members: nil,
description: nil,
banner: nil,
premium_tier: nil,
premium_subscription_count: nil,
preferred_locale: nil,
max_video_channel_users: nil,
max_stage_video_channel_users: nil,
welcome_screen: nil,
nsfw_level: nil,
premium_progress_bar_enabled: nil,
safety_alerts_channel_id: nil
}

@typedoc """
Expand Down Expand Up @@ -309,7 +426,22 @@ defmodule Nostrum.Struct.Guild do
guild_scheduled_events: guild_scheduled_events,
vanity_url_code: vanity_url_code,
threads: threads,
stickers: stickers
stickers: stickers,
discovery_splash: discovery_splash,
system_channel_flags: system_channel_flags,
max_presences: max_presences,
max_members: max_members,
description: description,
banner: banner,
premium_tier: premium_tier,
premium_subscription_count: premium_subscription_count,
preferred_locale: preferred_locale,
max_video_channel_users: max_video_channel_users,
max_stage_video_channel_users: max_stage_video_channel_users,
welcome_screen: welcome_screen,
nsfw_level: nsfw_level,
premium_progress_bar_enabled: premium_progress_bar_enabled,
safety_alerts_channel_id: safety_alerts_channel_id
}

@type t ::
Expand Down Expand Up @@ -372,6 +504,52 @@ defmodule Nostrum.Struct.Guild do
def splash_url(%__MODULE__{splash: splash, id: id}, image_format),
do: URI.encode(Constants.cdn_url() <> Constants.cdn_splash(id, splash, image_format))

@doc ~S"""
Returns the URL of the guild's discovery splash, or `nil` if no discovery splash.
Supported image formats are PNG, JPEG and WebP.
## Examples
```elixir
iex> guild = %Nostrum.Struct.Guild{discovery_splash: "656477617264736e6f7764656e",
...> id: 112233445566778899}
iex> Nostrum.Struct.Guild.discovery_splash_url(guild)
"https://cdn.discordapp.com/discovery-splashes/112233445566778899/656477617264736e6f7764656e.webp"
iex> Nostrum.Struct.Guild.discovery_splash_url(guild, "png")
"https://cdn.discordapp.com/discovery-splashes/112233445566778899/656477617264736e6f7764656e.png"
```
"""
@spec discovery_splash_url(t, String.t()) :: String.t() | nil
def discovery_splash_url(guild, image_format \\ "webp")
def discovery_splash_url(%__MODULE__{discovery_splash: nil}, _), do: nil

def discovery_splash_url(%__MODULE__{discovery_splash: dsp, id: id}, image_format),
do: Constants.cdn_url() <> Constants.cdn_discovery_splash(id, dsp, image_format)

@doc ~S"""
Returns the URL of the guild's banner, or `nil` if no guild banner has been set.
Supported image formats are PNG, GIF, JPEG and WebP.
## Examples
```elixir
iex> guild = %Nostrum.Struct.Guild{banner: "656477617264736e6f7764656e",
...> id: 112233445566778899}
iex> Nostrum.Struct.Guild.banner_url(guild)
"https://cdn.discordapp.com/banners/112233445566778899/656477617264736e6f7764656e.webp"
iex> Nostrum.Struct.Guild.banner_url(guild, "png")
"https://cdn.discordapp.com/banners/112233445566778899/656477617264736e6f7764656e.png"
```
"""
@spec discovery_splash_url(t, String.t()) :: String.t() | nil
def banner_url(guild, image_format \\ "webp")
def banner_url(%__MODULE__{banner: nil}, _), do: nil

def banner_url(%__MODULE__{banner: banner, id: id}, image_format),
do: Constants.cdn_url() <> Constants.cdn_guild_banner(id, banner, image_format)

@doc false
def p_encode do
%__MODULE__{}
Expand Down Expand Up @@ -401,10 +579,23 @@ defmodule Nostrum.Struct.Guild do
&Util.cast(&1, {:list, {:struct, ScheduledEvent}})
)
|> Map.update(:threads, nil, &Util.cast(&1, {:index, [:id], {:struct, Channel}}))
|> Map.update(:safety_alerts_channel_id, nil, &Util.cast(&1, Snowflake))
|> Map.update(:nsfw_level, nil, &cast_nsfw_level/1)
|> Map.put_new(:premium_subscription_count, 0)

struct(__MODULE__, new)
end

@doc false
defp cast_nsfw_level(level) do
case level do
0 -> :default
1 -> :explicit
2 -> :safe
3 -> :age_restricted
end
end

@doc false
@spec merge(t, t) :: t
def merge(old_guild, new_guild) do
Expand Down
110 changes: 110 additions & 0 deletions lib/nostrum/struct/guild/system_channel_flags.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
defmodule Nostrum.Struct.Guild.SystemChannelFlags do
@moduledoc """
Struct representing the flags on a guild's system channel
"""

import Bitwise

defstruct suppress_join_notifications: false,
suppress_premium_subscriptions: false,
suppress_guild_reminder_notifications: false,
suppress_join_notification_replies: false,
suppress_role_subscription_purchase_notifications: false,
suppress_role_subscription_purchase_notification_replies: false

@typedoc "Suppress member join notifications"
@type suppress_join_notifications :: boolean

@typedoc "Suppress server boost notifications"
@type suppress_premium_subscriptions :: boolean

@typedoc "Suppress server setup tips"
@type suppress_guild_reminder_notifications :: boolean

@typedoc "Hide member join sticker reply buttons"
@type suppress_join_notification_replies :: boolean

@typedoc "Suppress role subscription purchase and renewal notifications"
@type suppress_role_subscription_purchase_notifications :: boolean

@typedoc "Hide role subscription sticker reply buttons"
@type suppress_role_subscription_purchase_notifications_replies :: boolean

@type flags :: %__MODULE__{
suppress_join_notifications: suppress_join_notifications,
suppress_premium_subscriptions: suppress_premium_subscriptions,
suppress_guild_reminder_notifications: suppress_guild_reminder_notifications,
suppress_join_notification_replies: suppress_join_notification_replies,
suppress_role_subscription_purchase_notifications:
suppress_role_subscription_purchase_notifications,
suppress_role_subscription_purchase_notification_replies:
suppress_role_subscription_purchase_notifications_replies
}

@type t :: flags

@flag_values [
suppress_join_notifications: 1 <<< 0,
suppress_premium_subscriptions: 1 <<< 1,
suppress_guild_reminder_notifications: 1 <<< 2,
suppress_join_notification_replies: 1 <<< 3,
suppress_role_subscription_purchase_notifications: 1 <<< 4,
suppress_role_subscription_purchase_notification_replies: 1 <<< 5
]

@doc """
Constructs a flag struct based on an integer from the Discord API, normally from `t:Nostrum.Struct.Guild.Member.flags/0`.
## Examples
```elixir
iex> Nostrum.Struct.Guild.SystemChannelFlags.from_integer(3)
%Nostrum.Struct.Guild.SystemChannelFlags{
suppress_guild_reminder_notifications: false,
suppress_join_notification_replies: false,
suppress_join_notifications: true,
suppress_premium_subscriptions: true,
suppress_role_subscription_purchase_notification_replies: false,
suppress_role_subscription_purchase_notifications: false
}
```
"""
@spec from_integer(integer()) :: t
def from_integer(flag_value) do
boolean_list =
Enum.map(@flag_values, fn {flag, value} ->
{flag, (flag_value &&& value) == value}
end)

struct(__MODULE__, boolean_list)
end

@doc """
Convert a flag struct to an integer value.
## Examples
```elixir
iex> my_flags = %Nostrum.Struct.Guild.SystemChannelFlags{
...> suppress_join_notifications: true,
...> suppress_join_notification_replies: true
...> }
iex> Nostrum.Struct.Guild.SystemChannelFlags.to_integer(my_flags)
9
```
"""
@spec to_integer(t) :: integer()
def to_integer(flag_struct) do
booleans =
flag_struct
|> Map.from_struct()
|> Map.to_list()

Enum.reduce(booleans, 0, fn {flag, enabled}, flag_value ->
case enabled do
true -> flag_value ||| @flag_values[flag]
false -> flag_value
end
end)
end
end
7 changes: 7 additions & 0 deletions test/nostrum/struct/guild/system_channel_flags_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Nostrum.Struct.Guild.SystemChannelFlagsTest do
use ExUnit.Case, async: true

alias Nostrum.Struct.Guild.SystemChannelFlags

doctest SystemChannelFlags
end

0 comments on commit 45c892e

Please # to comment.