From d8c154a36a561af70e8ef9e0aca3776191e64314 Mon Sep 17 00:00:00 2001 From: Filip Hoffmann Date: Wed, 16 Jul 2025 00:50:45 +0200 Subject: [PATCH] remove guild.Member (put into its own module), get guild active threads endpoint --- src/grom/channel.gleam | 1 + src/grom/channel/thread.gleam | 6 +- src/grom/guild.gleam | 155 +++++++--------------------------- src/grom/guild_member.gleam | 137 ++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 127 deletions(-) create mode 100644 src/grom/guild_member.gleam diff --git a/src/grom/channel.gleam b/src/grom/channel.gleam index 20fe4ef..3ca23d8 100644 --- a/src/grom/channel.gleam +++ b/src/grom/channel.gleam @@ -371,6 +371,7 @@ pub type VideoQualityMode { pub type ReceivedThreads { ReceivedThreads( threads: List(Thread), + // TODO: Rename to current_members or something members: List(thread.Member), has_more: Bool, ) diff --git a/src/grom/channel/thread.gleam b/src/grom/channel/thread.gleam index 9007018..0729192 100644 --- a/src/grom/channel/thread.gleam +++ b/src/grom/channel/thread.gleam @@ -11,7 +11,7 @@ import gleam/time/duration.{type Duration} import gleam/time/timestamp.{type Timestamp} import grom/client.{type Client} import grom/error.{type Error} -import grom/guild +import grom/guild_member.{type GuildMember} import grom/internal/flags import grom/internal/rest import grom/internal/time_duration @@ -89,7 +89,7 @@ pub type Member { thread_id: Option(String), user_id: Option(String), join_timestamp: Timestamp, - guild_member: Option(guild.Member), + guild_member: Option(GuildMember), ) } @@ -220,7 +220,7 @@ pub fn member_decoder() -> decode.Decoder(Member) { use guild_member <- decode.optional_field( "member", None, - decode.optional(guild.member_decoder()), + decode.optional(guild_member.decoder()), ) decode.success(Member(thread_id:, user_id:, join_timestamp:, guild_member:)) } diff --git a/src/grom/guild.gleam b/src/grom/guild.gleam index 3bff500..bc2f24e 100644 --- a/src/grom/guild.gleam +++ b/src/grom/guild.gleam @@ -2,12 +2,14 @@ import gleam/bool import gleam/dynamic/decode import gleam/http import gleam/http/request +import gleam/http/response import gleam/int import gleam/json.{type Json} import gleam/list import gleam/option.{type Option, None, Some} import gleam/result import gleam/time/timestamp.{type Timestamp} +import grom/channel/thread.{type Thread} import grom/client.{type Client} import grom/emoji.{type Emoji} import grom/error.{type Error} @@ -162,37 +164,6 @@ pub type NsfwLevel { NsfwAgeRestricted } -pub type Member { - Member( - user: Option(User), - nick: Option(String), - avatar_hash: Option(String), - banner_hash: Option(String), - roles: List(String), - joined_at: Timestamp, - premium_since: Option(Timestamp), - is_deaf: Option(Bool), - is_mute: Option(Bool), - flags: List(MemberFlag), - is_pending: Option(Bool), - permissions: Option(String), - communication_disabled_until: Option(Timestamp), - avatar_decoration_data: Option(user.AvatarDecorationData), - ) -} - -pub type MemberFlag { - MemberDidRejoin - MemberCompletedOnboarding - MemberBypassesVerification - MemberStartedOnboarding - MemberIsGuest - MemberStartedHomeActions - MemberCompletedHomeActions - MemberQuarantinedBecauseOfUsername - MemberAcknowledgedDmSettingsUpsell -} - pub type Preview { Preview( id: String, @@ -271,6 +242,10 @@ pub opaque type Modify { ) } +pub type ReceivedThreads { + ReceivedThreads(threads: List(Thread), current_members: List(thread.Member)) +} + // FLAGS ------------------------------------------------------------------ @internal @@ -291,21 +266,6 @@ pub fn bits_system_channel_flags() -> List(#(Int, SystemChannelFlag)) { ] } -@internal -pub fn bits_member_flags() { - [ - #(int.bitwise_shift_left(1, 0), MemberDidRejoin), - #(int.bitwise_shift_left(1, 1), MemberCompletedOnboarding), - #(int.bitwise_shift_left(1, 2), MemberBypassesVerification), - #(int.bitwise_shift_left(1, 3), MemberStartedOnboarding), - #(int.bitwise_shift_left(1, 4), MemberIsGuest), - #(int.bitwise_shift_left(1, 5), MemberStartedHomeActions), - #(int.bitwise_shift_left(1, 6), MemberCompletedHomeActions), - #(int.bitwise_shift_left(1, 7), MemberQuarantinedBecauseOfUsername), - #(int.bitwise_shift_left(1, 9), MemberAcknowledgedDmSettingsUpsell), - ] -} - // DECODERS ------------------------------------------------------------------- @internal @@ -676,84 +636,6 @@ pub fn ban_decoder() -> decode.Decoder(Ban) { decode.success(Ban(reason:, user:)) } -@internal -pub fn member_decoder() -> decode.Decoder(Member) { - use user <- decode.optional_field( - "user", - None, - decode.optional(user.decoder()), - ) - use nick <- decode.optional_field( - "nick", - None, - decode.optional(decode.string), - ) - use avatar_hash <- decode.optional_field( - "avatar", - None, - decode.optional(decode.string), - ) - use banner_hash <- decode.optional_field( - "banner", - None, - decode.optional(decode.string), - ) - use roles <- decode.field("roles", decode.list(decode.string)) - use joined_at <- decode.field("joined_at", time_rfc3339.decoder()) - use premium_since <- decode.optional_field( - "premium_since", - None, - decode.optional(time_rfc3339.decoder()), - ) - use is_deaf <- decode.optional_field( - "deaf", - None, - decode.optional(decode.bool), - ) - use is_mute <- decode.optional_field( - "mute", - None, - decode.optional(decode.bool), - ) - use flags <- decode.field("flags", flags.decoder(bits_member_flags())) - use is_pending <- decode.optional_field( - "pending", - None, - decode.optional(decode.bool), - ) - use permissions <- decode.optional_field( - "permissions", - None, - decode.optional(decode.string), - ) - use communication_disabled_until <- decode.optional_field( - "communication_disabled_until", - None, - decode.optional(time_rfc3339.decoder()), - ) - use avatar_decoration_data <- decode.optional_field( - "avatar_decoration_data", - None, - decode.optional(user.avatar_decoration_data_decoder()), - ) - decode.success(Member( - user:, - nick:, - avatar_hash:, - banner_hash:, - roles:, - joined_at:, - premium_since:, - is_deaf:, - is_mute:, - flags:, - is_pending:, - permissions:, - communication_disabled_until:, - avatar_decoration_data:, - )) -} - @internal pub fn preview_decoder() -> decode.Decoder(Preview) { use id <- decode.field("id", decode.string) @@ -817,6 +699,16 @@ pub fn template_decoder() -> decode.Decoder(Template) { )) } +@internal +pub fn received_threads_decoder() -> decode.Decoder(ReceivedThreads) { + use threads <- decode.field("threads", decode.list(thread.decoder())) + use current_members <- decode.field( + "members", + decode.list(thread.member_decoder()), + ) + decode.success(ReceivedThreads(threads:, current_members:)) +} + // ENCODERS -------------------------------------------------------------------- @internal @@ -1391,3 +1283,18 @@ pub fn delete(client: Client, id guild_id: String) -> Result(Nil, Error) { Ok(Nil) } + +pub fn get_active_threads( + client: Client, + in guild_id: String, +) -> Result(ReceivedThreads, Error) { + use response <- result.try( + client + |> rest.new_request(http.Get, "/guilds/" <> guild_id <> "/threads/active") + |> rest.execute, + ) + + response.body + |> json.parse(using: received_threads_decoder()) + |> result.map_error(error.CouldNotDecode) +} diff --git a/src/grom/guild_member.gleam b/src/grom/guild_member.gleam new file mode 100644 index 0000000..205d7e0 --- /dev/null +++ b/src/grom/guild_member.gleam @@ -0,0 +1,137 @@ +import gleam/dynamic/decode +import gleam/int +import gleam/option.{type Option, None} +import gleam/time/timestamp.{type Timestamp} +import grom/internal/flags +import grom/internal/time_rfc3339 +import grom/user.{type User} + +// TYPES ----------------------------------------------------------------------- + +pub type GuildMember { + Member( + user: Option(User), + nick: Option(String), + avatar_hash: Option(String), + banner_hash: Option(String), + roles: List(String), + joined_at: Timestamp, + premium_since: Option(Timestamp), + is_deaf: Option(Bool), + is_mute: Option(Bool), + flags: List(Flag), + is_pending: Option(Bool), + permissions: Option(String), + communication_disabled_until: Option(Timestamp), + avatar_decoration_data: Option(user.AvatarDecorationData), + ) +} + +pub type Flag { + DidRejoin + CompletedOnboarding + BypassesVerification + StartedOnboarding + IsGuest + StartedHomeActions + CompletedHomeActions + QuarantinedBecauseOfUsername + AcknowledgedDmSettingsUpsell +} + +// FLAGS ----------------------------------------------------------------------- + +@internal +pub fn bits_member_flags() { + [ + #(int.bitwise_shift_left(1, 0), DidRejoin), + #(int.bitwise_shift_left(1, 1), CompletedOnboarding), + #(int.bitwise_shift_left(1, 2), BypassesVerification), + #(int.bitwise_shift_left(1, 3), StartedOnboarding), + #(int.bitwise_shift_left(1, 4), IsGuest), + #(int.bitwise_shift_left(1, 5), StartedHomeActions), + #(int.bitwise_shift_left(1, 6), CompletedHomeActions), + #(int.bitwise_shift_left(1, 7), QuarantinedBecauseOfUsername), + #(int.bitwise_shift_left(1, 9), AcknowledgedDmSettingsUpsell), + ] +} + +// DECODERS -------------------------------------------------------------------- + +@internal +pub fn decoder() -> decode.Decoder(GuildMember) { + use user <- decode.optional_field( + "user", + None, + decode.optional(user.decoder()), + ) + use nick <- decode.optional_field( + "nick", + None, + decode.optional(decode.string), + ) + use avatar_hash <- decode.optional_field( + "avatar", + None, + decode.optional(decode.string), + ) + use banner_hash <- decode.optional_field( + "banner", + None, + decode.optional(decode.string), + ) + use roles <- decode.field("roles", decode.list(decode.string)) + use joined_at <- decode.field("joined_at", time_rfc3339.decoder()) + use premium_since <- decode.optional_field( + "premium_since", + None, + decode.optional(time_rfc3339.decoder()), + ) + use is_deaf <- decode.optional_field( + "deaf", + None, + decode.optional(decode.bool), + ) + use is_mute <- decode.optional_field( + "mute", + None, + decode.optional(decode.bool), + ) + use flags <- decode.field("flags", flags.decoder(bits_member_flags())) + use is_pending <- decode.optional_field( + "pending", + None, + decode.optional(decode.bool), + ) + use permissions <- decode.optional_field( + "permissions", + None, + decode.optional(decode.string), + ) + use communication_disabled_until <- decode.optional_field( + "communication_disabled_until", + None, + decode.optional(time_rfc3339.decoder()), + ) + use avatar_decoration_data <- decode.optional_field( + "avatar_decoration_data", + None, + decode.optional(user.avatar_decoration_data_decoder()), + ) + decode.success(Member( + user:, + nick:, + avatar_hash:, + banner_hash:, + roles:, + joined_at:, + premium_since:, + is_deaf:, + is_mute:, + flags:, + is_pending:, + permissions:, + communication_disabled_until:, + avatar_decoration_data:, + )) +} -- 2.51.2