diff --git a/extra/admin-api/Models/Spacebar.Models.Api/LoginRequest.cs b/extra/admin-api/Models/Spacebar.Models.Api/LoginRequest.cs
new file mode 100644
index 00000000..6971d55e
--- /dev/null
+++ b/extra/admin-api/Models/Spacebar.Models.Api/LoginRequest.cs
@@ -0,0 +1,79 @@
+using System.Text.Json.Serialization;
+
+namespace Spacebar.Models.Api;
+
+public class LoginRequest {
+ [JsonPropertyName("login")]
+ public required string Login { get; set; }
+
+ [JsonPropertyName("password")]
+ public required string Password { get; set; }
+
+ /// <summary>
+ /// Whether to un-delete a self-disabled or self-deleted account
+ /// </summary>
+ [JsonPropertyName("undelete")]
+ public bool? Undelete { get; set; }
+
+ /// <summary>
+ /// One of gift, guild_template, guild_invite, dm_invite, friend_invite, role_subscription or role_subscription_setting
+ /// </summary>
+ [JsonPropertyName("login_source")]
+ public string? LoginSource { get; set; }
+
+ [JsonPropertyName("gift_code_sku_id")]
+ public string? GiftCodeSkuId { get; set; }
+}
+
+/// <summary>
+/// Note: nullable fields missing "if the login was not completed"
+/// </summary>
+public class LoginResponse {
+ [JsonPropertyName("user_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public ulong UserId { get; set; }
+
+ [JsonPropertyName("token")]
+ public string? Token { get; set; }
+
+ [JsonPropertyName("user_settings")]
+ public LoginUserSettings? UserSettings { get; set; }
+
+ /// <summary>
+ /// Values: update_password
+ /// </summary>
+ [JsonPropertyName("required_actions")]
+ public List<string>? RequiredActions { get; set; }
+
+ /// <summary>
+ /// MFA ticket
+ /// </summary>
+ [JsonPropertyName("ticket")]
+ public string? Ticket { get; set; }
+
+ [JsonPropertyName("login_instance_id")]
+ public string? LoginInstanceId { get; set; }
+
+ [JsonPropertyName("mfa")]
+ public bool? Mfa { get; set; }
+
+ [JsonPropertyName("totp")]
+ public bool? Totp { get; set; }
+
+ [JsonPropertyName("sms")]
+ public bool? Sms { get; set; }
+
+ [JsonPropertyName("backup")]
+ public bool? Backup { get; set; }
+
+ [JsonPropertyName("webauthn")]
+ public string? Webauthn { get; set; }
+
+
+ public class LoginUserSettings {
+ [JsonPropertyName("locale")]
+ public string Locale { get; set; }
+
+ [JsonPropertyName("theme")]
+ public string Theme { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/extra/admin-api/Models/Spacebar.Models.Api/Spacebar.Models.Api.csproj b/extra/admin-api/Models/Spacebar.Models.Api/Spacebar.Models.Api.csproj
new file mode 100644
index 00000000..237d6616
--- /dev/null
+++ b/extra/admin-api/Models/Spacebar.Models.Api/Spacebar.Models.Api.csproj
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net10.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+</Project>
diff --git a/extra/admin-api/Models/Spacebar.Models.Api/SpacebarApiError.cs b/extra/admin-api/Models/Spacebar.Models.Api/SpacebarApiError.cs
new file mode 100644
index 00000000..03bf9264
--- /dev/null
+++ b/extra/admin-api/Models/Spacebar.Models.Api/SpacebarApiError.cs
@@ -0,0 +1,29 @@
+using System.Text.Json.Nodes;
+
+namespace Spacebar.Models.Api;
+
+public class SpacebarApiException : Exception {
+ public int Code { get; set; }
+ public string? Request { get; set; } // Spacebar extension
+ // public Dictionary<string, FieldErrorList> Errors { get; set; }
+ public JsonObject? Errors { get; set; }
+
+ public class FieldErrorList {
+ // public
+ }
+
+ public SpacebarApiException(string? message) : base(message) {
+
+ }
+
+ // TODO: abstract out to HTTP layer
+ public static SpacebarApiException FromJson(JsonObject resp) {
+ var ex = new SpacebarApiException(resp["message"]!.GetValue<string>()) {
+ Code = resp["code"]!.GetValue<int>(),
+ Request = resp["request"]?.GetValue<string>(),
+ Errors = resp["errors"]?.AsObject()
+ };
+
+ return ex;
+ }
+}
\ No newline at end of file
diff --git a/extra/admin-api/Models/Spacebar.Models.Gateway/GatewayPayload.cs b/extra/admin-api/Models/Spacebar.Models.Gateway/GatewayPayload.cs
new file mode 100644
index 00000000..1a5d2c86
--- /dev/null
+++ b/extra/admin-api/Models/Spacebar.Models.Gateway/GatewayPayload.cs
@@ -0,0 +1,83 @@
+using System.Diagnostics;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
+
+namespace Spacebar.Models.Gateway;
+
+public class GatewayPayload {
+ [JsonPropertyName("op")]
+ public GatewayOpcode Opcode { get; set; }
+
+ [JsonPropertyName("d")]
+ public JsonObject? EventData { get; set; }
+
+ [JsonPropertyName("s")]
+ public int? Sequence { get; set; }
+
+ [JsonPropertyName("t")]
+ public string? DispatchEventType { get; set; }
+
+ public T? GetData<T>() where T : class {
+ if (EventData is null) return null;
+ var sw = Stopwatch.StartNew();
+ var jso = new JsonSerializerOptions();
+ if (typeof(T) == typeof(ReadyResponse)) {
+ Console.WriteLine("Adding ReadyResponse sourcegen");
+ jso.TypeInfoResolver = new ReadyResponseSerializerContext();
+ }
+ else
+ Console.WriteLine($"No TypeInfoResolver for {typeof(T).FullName}");
+
+ var deserialized = EventData.Deserialize<T>(jso);
+ Console.WriteLine($"Deserialized {typeof(T).FullName} in {sw.Elapsed}");
+ return deserialized;
+ }
+}
+
+public enum GatewayOpcode {
+ S2CDispatch,
+ Heartbeat,
+ C2SIdentify,
+ C2SPresenceUpdate,
+ C2SVoiceStateUpdate,
+ C2SVoiceServerPing,
+ C2SResume,
+ S2CReconnect,
+ C2SRequestGuildMembers,
+ S2CInvalidSession,
+ S2CHello,
+ S2CHeartbeatAck,
+ C2SGuildSync,
+ C2SCallConnect,
+ C2SGuildSubscriptions,
+ C2SLobbyConnect,
+ C2SLobbyDisconnect,
+ C2SLobbyVoiceStates,
+ C2SStreamCreate,
+ C2SStreamDelete,
+ C2SStreamWatch,
+ C2SStreamPing,
+ C2SStreamSetPaused,
+ C2SLfgSubscription,
+ C2SRequestGuildApplicationCommands,
+ C2SEmbeddedActivityCreate,
+ C2SEmbeddedActivityDelete,
+ C2SEmbeddedActivityUpdate,
+ C2SRequestForumUnreads,
+ C2SRemoteCommand,
+ C2SRequestDeletedEntityIds,
+ C2SRequestSoundboardSounds,
+ C2SSpeedTestCreate,
+ C2SSpeedTestDelete,
+ C2SRequestLastMessages,
+ C2SSearchRecentMembers,
+ C2SRequestChannelStatuses,
+ C2SGuildSubscriptionsBulk,
+ C2SGuildChannelsResync,
+ C2SRequestChannelMemberCount,
+ C2SQoSHeartbeat,
+ C2SUpdateTimeSpentSessionId,
+ C2SLobbyVoiceServerPing,
+ C2SRequestChannelInfo
+}
\ No newline at end of file
diff --git a/extra/admin-api/Models/Spacebar.Models.Gateway/IdentifyRequest.cs b/extra/admin-api/Models/Spacebar.Models.Gateway/IdentifyRequest.cs
index ee39e292..f94ebecd 100644
--- a/extra/admin-api/Models/Spacebar.Models.Gateway/IdentifyRequest.cs
+++ b/extra/admin-api/Models/Spacebar.Models.Gateway/IdentifyRequest.cs
@@ -3,6 +3,11 @@ using System.Text.Json.Serialization;
namespace Spacebar.Models.Gateway;
+public class HelloResponse {
+ [JsonPropertyName("heartbeat_interval")]
+ public int HeartbeatInterval { get; set; }
+}
+
public class IdentifyRequest {
[JsonPropertyName("token")]
public string Token { get; set; }
@@ -32,6 +37,171 @@ public class IdentifyRequest {
public JsonObject? ClientState { get; set; }
}
+/// <summary>
+/// This class defines all client properties used by discord
+/// This should *not* be used as a schema, as the types are merely conventions, and the structure isn't well-defined.
+/// </summary>
+public class IdentifyClientProperties {
+ [JsonPropertyName("os")]
+ public string? OperatingSystem { get; set; }
+
+ [JsonPropertyName("os_version")]
+ public string? OperatingSystemVersion { get; set; }
+
+ [JsonPropertyName("os_sdk_version")]
+ public string? OperatingSystemSdkVersion { get; set; }
+
+ [JsonPropertyName("os_arch")]
+ public string? OperatingSystemArchitecture { get; set; }
+
+ [JsonPropertyName("app_arch")]
+ public string? ApplicationArchitecture { get; set; }
+
+ [JsonPropertyName("browser")]
+ public string? Browser { get; set; }
+
+ [JsonPropertyName("browser_user_agent")]
+ public string? BrowserUserAgent { get; set; }
+
+ [JsonPropertyName("browser_version")]
+ public string? BrowserVersion { get; set; }
+
+ [JsonPropertyName("client_build_number")]
+ public int? ClientBuildNumber { get; set; }
+
+ [JsonPropertyName("native_build_number")]
+ public int? NativeBuildNumber { get; set; }
+
+ [JsonPropertyName("client_version")]
+ public string? ClientVersion { get; set; }
+
+ [JsonPropertyName("client_event_source")]
+ public string? ClientEventSource { get; set; }
+
+ [JsonPropertyName("client_app_state")]
+ public string? ClientAppState { get; set; }
+
+ [JsonPropertyName("client_launch_id")]
+ public string? ClientLaunchId { get; set; }
+
+ [JsonPropertyName("client_heartbeat_session_id")]
+ public string? ClientHeartbeatSessionId { get; set; }
+
+ [JsonPropertyName("client_performance_cpu")]
+ public int? ClientPerformanceCpu { get; set; }
+
+ [JsonPropertyName("client_performance_memory")]
+ public int? ClientPerformanceMemory { get; set; }
+
+ [JsonPropertyName("cpu_core_count")]
+ public int? CpuCoreCount { get; set; }
+
+ [JsonPropertyName("release_channel")]
+ public string? ReleaseChannel { get; set; }
+
+ [JsonPropertyName("system_locale")]
+ public string? SystemLocale { get; set; }
+
+ [JsonPropertyName("device")]
+ public string? DeviceModel { get; set; }
+
+ [JsonPropertyName("device_vendor_id")]
+ public string? DeviceVendorId { get; set; }
+
+ [JsonPropertyName("device_advertiser_id")]
+ public string? DeviceAdvertiserId { get; set; }
+
+ [JsonPropertyName("design_id")]
+ public int? DesignId { get; set; }
+
+ [JsonPropertyName("accessibility_support_enabled")]
+ public string? AccessibilitySupportEnabled { get; set; }
+
+ [JsonPropertyName("accessibility_features")]
+ public int? AccessibilityFeatures { get; set; }
+
+ [JsonPropertyName("window_manager")]
+ public string? WindowManager { get; set; }
+
+ [JsonPropertyName("distro")]
+ public string? Distro { get; set; }
+
+ [JsonPropertyName("runtime_environment")]
+ public string? RuntimeEnvironment { get; set; }
+
+ [JsonPropertyName("display_server")]
+ public string? DisplayServer { get; set; }
+
+ [JsonPropertyName("referrer")]
+ public string? Referrer { get; set; }
+
+ [JsonPropertyName("referrer_current")]
+ public string? ReferrerCurrent { get; set; }
+
+ [JsonPropertyName("referring_domain")]
+ public string? ReferringDomain { get; set; }
+
+ [JsonPropertyName("referring_domain_current")]
+ public string? ReferringDomainCurrent { get; set; }
+
+ [JsonPropertyName("search_engine")]
+ public string? SearchEngine { get; set; }
+
+ [JsonPropertyName("search_engine_current")]
+ public string? SearchEngineCurrent { get; set; }
+
+ [JsonPropertyName("mp_keyword")]
+ public string? MpKeyword { get; set; }
+
+ [JsonPropertyName("mp_keyword_current")]
+ public string? MpKeywordCurrent { get; set; }
+
+ [JsonPropertyName("utm_campaign")]
+ public string? UtmCampaign { get; set; }
+
+ [JsonPropertyName("utm_campaign_current")]
+ public string? UtmCampaignCurrent { get; set; }
+
+ [JsonPropertyName("utm_content")]
+ public string? UtmContent { get; set; }
+
+ [JsonPropertyName("utm_content_current")]
+ public string? UtmContentCurrent { get; set; }
+
+ [JsonPropertyName("utm_medium")]
+ public string? UtmMedium { get; set; }
+
+ [JsonPropertyName("utm_medium_current")]
+ public string? UtmMediumCurrent { get; set; }
+
+ [JsonPropertyName("utm_source")]
+ public string? UtmSource { get; set; }
+
+ [JsonPropertyName("utm_source_current")]
+ public string? UtmSourceCurrent { get; set; }
+
+ [JsonPropertyName("utm_term")]
+ public string? UtmTerm { get; set; }
+
+ [JsonPropertyName("utm_term_current")]
+ public string? UtmTermCurrent { get; set; }
+
+ [JsonPropertyName("has_client_mods")]
+ public bool? HasClientMods { get; set; }
+
+ [JsonPropertyName("launch_signature")]
+ public string? LaunchSignature { get; set; }
+
+ [JsonPropertyName("installation_id")]
+ public string? InstallationId { get; set; }
+
+ [JsonPropertyName("is_fast_connect")]
+ public bool? IsFastConnect { get; set; }
+
+ [JsonPropertyName("version")]
+ public string? Version { get; set; }
+}
+
[Flags]
public enum GatewayIntentFlags : ulong {
Guilds = 1,
diff --git a/extra/admin-api/Models/Spacebar.Models.Gateway/QoSPayload.cs b/extra/admin-api/Models/Spacebar.Models.Gateway/QoSPayload.cs
index efb8dff9..e470318b 100644
--- a/extra/admin-api/Models/Spacebar.Models.Gateway/QoSPayload.cs
+++ b/extra/admin-api/Models/Spacebar.Models.Gateway/QoSPayload.cs
@@ -2,6 +2,16 @@ using System.Text.Json.Serialization;
namespace Spacebar.Models.Gateway;
+public class HeartbeatRequest {
+ [JsonPropertyName("seq")]
+ public required int? Sequence { get; set; }
+}
+
+public class QoSHeartbeatRequest : HeartbeatRequest {
+ [JsonPropertyName("qos")]
+ public required QoSPayload QoSPayload { get; set; }
+}
+
public class QoSPayload {
[JsonPropertyName("ver")]
public int Version { get; set; }
diff --git a/extra/admin-api/Models/Spacebar.Models.Gateway/ReadyResponse.cs b/extra/admin-api/Models/Spacebar.Models.Gateway/ReadyResponse.cs
index 5573cdb5..d26fecf6 100644
--- a/extra/admin-api/Models/Spacebar.Models.Gateway/ReadyResponse.cs
+++ b/extra/admin-api/Models/Spacebar.Models.Gateway/ReadyResponse.cs
@@ -1,3 +1,37 @@
+using System.Text.Json.Serialization;
+using Spacebar.Models.Generic;
+
namespace Spacebar.Models.Gateway;
-public class ReadyResponse { }
\ No newline at end of file
+public class ReadyResponse {
+ /* TODO: _trace, analytics_token, api_code_version, auth_session_id_hash, connected_accounts, consents, country_code, experiments, friend_suggestion_count, game_relationships,
+ geo_ordered_rtc_regions, guild_experiments, guild_join_requests*/
+ [JsonPropertyName("guilds")]
+ public required List<Guild> Guilds { get; set; }
+
+ [JsonPropertyName("merged_members")]
+ public List<List<Member>> MergedMembers { get; set; }
+
+ // TODO: notification_settings
+
+ [JsonPropertyName("presences")]
+ public List<Presence> Presences { get; set; } // TODO: right type?
+
+ [JsonPropertyName("private_channels")]
+ public List<Channel> PrivateChannels { get; set; }
+
+ [JsonPropertyName("read_state")]
+ public object ReadStates { get; set; } // TODO: schemas
+
+ [JsonPropertyName("relationships")]
+ public List<object> Relationships { get; set; } // TODO: schemas
+
+ [JsonPropertyName("resume_gateway_url")]
+ public string ResumeGatewayUrl { get; set; }
+}
+
+[JsonSourceGenerationOptions()]
+[JsonSerializable(typeof(ReadyResponse))]
+public partial class ReadyResponseSerializerContext : JsonSerializerContext
+{
+}
\ No newline at end of file
diff --git a/extra/admin-api/Models/Spacebar.Models.Generic/Channel.cs b/extra/admin-api/Models/Spacebar.Models.Generic/Channel.cs
index 857d2e78..01a91c64 100644
--- a/extra/admin-api/Models/Spacebar.Models.Generic/Channel.cs
+++ b/extra/admin-api/Models/Spacebar.Models.Generic/Channel.cs
@@ -2,6 +2,10 @@ using System.Text.Json.Serialization;
namespace Spacebar.Models.Generic;
+public class Channel {
+
+}
+
public class ChannelPermissionOverwrite {
[JsonPropertyName("id")]
public string Id { get; set; }
diff --git a/extra/admin-api/Models/Spacebar.Models.Generic/Emoji.cs b/extra/admin-api/Models/Spacebar.Models.Generic/Emoji.cs
new file mode 100644
index 00000000..c47d2a78
--- /dev/null
+++ b/extra/admin-api/Models/Spacebar.Models.Generic/Emoji.cs
@@ -0,0 +1,35 @@
+using System.Text.Json.Serialization;
+
+namespace Spacebar.Models.Generic;
+
+public class Emoji {
+ [JsonPropertyName("id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long Id { get; set; }
+
+ [JsonPropertyName("animated")]
+ public bool Animated { get; set; }
+
+ [JsonPropertyName("available")]
+ public bool Available { get; set; }
+
+ [JsonPropertyName("groups")]
+ public object? Groups { get; set; } // TODO: what is this?
+
+ [JsonPropertyName("guild_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long GuildId { get; set; }
+
+ [JsonPropertyName("managed")]
+ public bool Managed { get; set; }
+
+ [JsonPropertyName("name")]
+ public required string Name { get; set; }
+
+ [JsonPropertyName("require_colons")]
+ public bool RequireColons { get; set; }
+
+ [JsonPropertyName("roles")]
+ public List<object?> Roles { get; set; } // TODO: what type was this again?
+
+ [JsonPropertyName("user_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long UserId { get; set; }
+}
\ No newline at end of file
diff --git a/extra/admin-api/Models/Spacebar.Models.Generic/Guild.cs b/extra/admin-api/Models/Spacebar.Models.Generic/Guild.cs
new file mode 100644
index 00000000..239fee5d
--- /dev/null
+++ b/extra/admin-api/Models/Spacebar.Models.Generic/Guild.cs
@@ -0,0 +1,133 @@
+using System.Diagnostics;
+using System.Text.Json.Serialization;
+
+namespace Spacebar.Models.Generic;
+
+[DebuggerDisplay("{Id} ({Name})")]
+public class Guild {
+ [JsonPropertyName("id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long Id { get; set; }
+
+ [JsonPropertyName("afk_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long? AfkChannelId { get; set; }
+
+ [JsonPropertyName("afk_timeout")]
+ public int AfkTimeout { get; set; }
+
+ [JsonPropertyName("banner")]
+ public string? Banner { get; set; }
+
+ [JsonPropertyName("channels")]
+ public List<Channel> Channels { get; set; }
+
+ [JsonPropertyName("default_message_notifications")]
+ public int DefaultMessageNotifications { get; set; } // TODO enum
+
+ [JsonPropertyName("description")]
+ public string? Description { get; set; }
+
+ [JsonPropertyName("discovery_splash")]
+ public string? DiscoverySplash { get; set; }
+
+ [JsonPropertyName("emojis")]
+ public List<Emoji> Emojis { get; set; }
+
+ [JsonPropertyName("explicit_content_filter")]
+ public int ExplicitContentFilter { get; set; }
+
+ [JsonPropertyName("features")]
+ public List<string> Features { get; set; }
+
+ [JsonPropertyName("guild_scheduled_events")]
+ public List<object> GuildScheduledEvents { get; set; } // TODO: implement
+
+ [JsonPropertyName("icon")]
+ public string? Icon { get; set; }
+
+ [JsonPropertyName("joined_at")]
+ public DateTimeOffset JoinedAt { get; set; }
+
+ [JsonPropertyName("large")]
+ public bool Large { get; set; }
+
+ [JsonPropertyName("max_members")]
+ public int MaxMembers { get; set; }
+
+ [JsonPropertyName("max_presences")]
+ public int MaxPresences { get; set; }
+
+ [JsonPropertyName("max_video_channel_users")]
+ public int MaxVideoChannelUsers { get; set; }
+
+ [JsonPropertyName("member_count")]
+ public int MemberCount { get; set; }
+
+ [JsonPropertyName("mfa_level")]
+ public int MfaLevel { get; set; }
+
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("nsfw_level")]
+ public int NsfwLevel { get; set; }
+
+ [JsonPropertyName("owner_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long OwnerId { get; set; }
+
+ [JsonPropertyName("preferred_locale")]
+ public string PreferredLocale { get; set; }
+
+ [JsonPropertyName("premium_progress_bar_enabled")]
+ public bool? PremiumProgressBarEnabled { get; set; }
+
+ [JsonPropertyName("premium_subscription_count")]
+ public int PremiumSubscriptionCount { get; set; }
+
+ [JsonPropertyName("premium_tier")]
+ public int PremiumTier { get; set; }
+
+ [JsonPropertyName("presences")]
+ public List<Presence> Presences { get; set; } // TODO: correct type?
+
+ [JsonPropertyName("public_updates_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public long? PublicUpdatesChannelId { get; set; }
+
+ [JsonPropertyName("region")]
+ public string Region { get; set; }
+
+ [JsonPropertyName("roles")]
+ public List<Role> Roles { get; set; }
+
+ [JsonPropertyName("rules_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public long? RulesChannelId { get; set; }
+
+ [JsonPropertyName("splash")]
+ public string? Splash { get; set; }
+
+ [JsonPropertyName("stickers")]
+ public List<Sticker> Stickers { get; set; }
+
+ [JsonPropertyName("system_channel_flags")]
+ public int SystemChannelFlags { get; set; } //TODO enum
+
+ [JsonPropertyName("system_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public long? SystemChannelId { get; set; }
+
+ [JsonPropertyName("threads")]
+ public List<Channel> Threads { get; set; }
+
+ [JsonPropertyName("verification_level")]
+ public int VerificationLevel { get; set; }
+
+ [JsonPropertyName("voice_states")]
+ public List<object> VoiceStates { get; set; } // TODO: models
+
+ [JsonPropertyName("welcome_screen")]
+ public object WelcomeScreen { get; set; } // TODO: models
+
+ [JsonPropertyName("widget_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public long? WidgetChannelId { get; set; }
+
+ [JsonPropertyName("widget_enabled")]
+ public bool WidgetEnabled { get; set; }
+}
\ No newline at end of file
diff --git a/extra/admin-api/Models/Spacebar.Models.Generic/Role.cs b/extra/admin-api/Models/Spacebar.Models.Generic/Role.cs
new file mode 100644
index 00000000..6c49f85e
--- /dev/null
+++ b/extra/admin-api/Models/Spacebar.Models.Generic/Role.cs
@@ -0,0 +1,62 @@
+using System.Text.Json.Serialization;
+using Spacebar.Models.Generic.Constants;
+
+namespace Spacebar.Models.Generic;
+
+public class Role {
+ [JsonPropertyName("id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long Id { get; set; }
+
+ [JsonPropertyName("color"), Obsolete("See Colors instead")]
+ public int Color { get; set; }
+
+ [JsonPropertyName("colors")]
+ public RoleColors Colors { get; set; }
+
+ [JsonPropertyName("flags")]
+ public int Flags { get; set; }
+
+ [JsonPropertyName("guild_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long GuildId { get; set; }
+
+ [JsonPropertyName("hoist")]
+ public bool Hoist { get; set; }
+
+ [JsonPropertyName("icon")]
+ public string Icon { get; set; }
+
+ [JsonPropertyName("managed")]
+ public bool Managed { get; set; }
+
+ [JsonPropertyName("mentionable")]
+ public bool Mentionable { get; set; }
+
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("permissions"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required ulong RawPermissions { get; set; }
+
+ [JsonIgnore]
+ public Permissions Permissions {
+ get => (Permissions)RawPermissions;
+ set => RawPermissions = (ulong)value;
+ }
+
+ [JsonPropertyName("position")]
+ public int Position { get; set; }
+
+ [JsonPropertyName("unicode_emoji")]
+ public string UnicodeEmoji { get; set; }
+
+ public class RoleColors {
+ [JsonPropertyName("primary_color")]
+ public required int PrimaryColor { get; set; }
+
+ [JsonPropertyName("secondary_color")]
+ public int? SecondaryColor { get; set; }
+
+ [JsonPropertyName("tertiary_color")]
+ public int? TertiaryColor { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/extra/admin-api/Models/Spacebar.Models.Generic/Sticker.cs b/extra/admin-api/Models/Spacebar.Models.Generic/Sticker.cs
new file mode 100644
index 00000000..28bf4feb
--- /dev/null
+++ b/extra/admin-api/Models/Spacebar.Models.Generic/Sticker.cs
@@ -0,0 +1,38 @@
+using System.Text.Json.Serialization;
+
+namespace Spacebar.Models.Generic;
+
+public class Sticker {
+ [JsonPropertyName("id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
+ public required long Id { get; set; }
+
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("description")]
+ public string Description { get; set; }
+
+ [JsonPropertyName("tags")]
+ public string Tags { get; set; }
+
+ [JsonPropertyName("available")]
+ public bool Available { get; set; }
+
+ [JsonPropertyName("type")]
+ public StickerType Type { get; set; }
+
+ [JsonPropertyName("format_type")]
+ public StickerFormatType FormatType { get; set; }
+}
+
+public enum StickerType {
+ Standard = 1,
+ Guild = 2
+}
+
+public enum StickerFormatType {
+ Png = 1,
+ Apng = 2,
+ Lottie = 3,
+ Gif = 4
+}
\ No newline at end of file
|