diff --git a/extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs b/extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs index 46ae248f6..ffd6c4fa3 100644 --- a/extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs +++ b/extra/admin-api/Interop/Spacebar.Interop.Authentication/SpacebarAuthenticationService.cs @@ -53,7 +53,7 @@ public class SpacebarAuthenticationService(ILogger { var uid = config.OverrideUid ?? res?.ClaimsIdentity.Claims.First(x => x.Type == "id").Value; if (string.IsNullOrWhiteSpace(uid)) throw new InvalidOperationException("No user ID specified, is the access token valid?"); - return await db.Users.FindAsync(uid) ?? throw new InvalidOperationException(); + return await db.Users.FindAsync(long.Parse(uid)) ?? throw new InvalidOperationException(); }, config.AuthCacheExpiry); } @@ -64,7 +64,7 @@ public class SpacebarAuthenticationService(ILogger { var did = config.OverrideDid ?? res?.ClaimsIdentity.Claims.First(x => x.Type == "did").Value; if (string.IsNullOrWhiteSpace(did)) throw new InvalidOperationException("No device ID specified, is the access token valid?"); - return await db.Sessions.FindAsync(did) ?? throw new InvalidOperationException(); + return await db.Sessions.FindAsync(long.Parse(did)) ?? throw new InvalidOperationException(); }, config.AuthCacheExpiry); } diff --git a/extra/admin-api/Models/Spacebar.Models.AdminApi/DiscoverableGuildModel.cs b/extra/admin-api/Models/Spacebar.Models.AdminApi/DiscoverableGuildModel.cs index fc75f7a09..6c529b417 100644 --- a/extra/admin-api/Models/Spacebar.Models.AdminApi/DiscoverableGuildModel.cs +++ b/extra/admin-api/Models/Spacebar.Models.AdminApi/DiscoverableGuildModel.cs @@ -120,8 +120,8 @@ public class DiscoverableGuildModel { [JsonPropertyName("premium_progress_bar_enabled")] public bool? PremiumProgressBarEnabled { get; set; } - [JsonPropertyName("channel_ordering")] - public List ChannelOrdering { get; set; } + [JsonPropertyName("channel_ordering"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] + public List ChannelOrdering { get; set; } [JsonPropertyName("discovery_weight")] public int DiscoveryWeight { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.AdminApi/GuildModel.cs b/extra/admin-api/Models/Spacebar.Models.AdminApi/GuildModel.cs index f4cad9d7d..0a2182a72 100644 --- a/extra/admin-api/Models/Spacebar.Models.AdminApi/GuildModel.cs +++ b/extra/admin-api/Models/Spacebar.Models.AdminApi/GuildModel.cs @@ -15,7 +15,7 @@ public class GuildModel { public string? Description { get; set; } public string? DiscoverySplash { get; set; } public int? ExplicitContentFilter { get; set; } - public string Features { get; set; } = null!; + public List Features { get; set; } = null!; [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public long? PrimaryCategoryId { get; set; } @@ -66,7 +66,9 @@ public class GuildModel { public bool Nsfw { get; set; } public string? Parent { get; set; } public bool? PremiumProgressBarEnabled { get; set; } - public string ChannelOrdering { get; set; } = null!; + + [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] + public List ChannelOrdering { get; set; } = null!; public int ChannelCount { get; set; } public int RoleCount { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.AdminApi/UserModel.cs b/extra/admin-api/Models/Spacebar.Models.AdminApi/UserModel.cs index 7e2590484..acba6a82b 100644 --- a/extra/admin-api/Models/Spacebar.Models.AdminApi/UserModel.cs +++ b/extra/admin-api/Models/Spacebar.Models.AdminApi/UserModel.cs @@ -11,7 +11,7 @@ public class UserModel { public string? Avatar { get; set; } public int? AccentColor { get; set; } public string? Banner { get; set; } - public string? ThemeColors { get; set; } + public List? ThemeColors { get; set; } public string? Pronouns { get; set; } public string? Phone { get; set; } public bool Desktop { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/Application.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/Application.cs index 921f108d6..9ee3811fd 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Models/Application.cs +++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/Application.cs @@ -44,8 +44,8 @@ public partial class Application [Column("flags")] public int Flags { get; set; } - [Column("redirect_uris")] - public string? RedirectUris { get; set; } + [Column("redirect_uris", TypeName = "character varying[]")] + public List? RedirectUris { get; set; } [Column("rpc_application_state")] public int? RpcApplicationState { get; set; } @@ -71,8 +71,8 @@ public partial class Application [Column("discovery_eligibility_flags")] public int? DiscoveryEligibilityFlags { get; set; } - [Column("tags")] - public string? Tags { get; set; } + [Column("tags", TypeName = "character varying[]")] + public List? Tags { get; set; } [Column("cover_image", TypeName = "character varying")] public string? CoverImage { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/AutomodRule.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/AutomodRule.cs index d0aebfce4..8dbb0be18 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Models/AutomodRule.cs +++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/AutomodRule.cs @@ -20,10 +20,10 @@ public partial class AutomodRule public int EventType { get; set; } [Column("exempt_channels")] - public string ExemptChannels { get; set; } = null!; + public List ExemptChannels { get; set; } = null!; [Column("exempt_roles")] - public string ExemptRoles { get; set; } = null!; + public List ExemptRoles { get; set; } = null!; [Column("guild_id")] public long GuildId { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/ConnectedAccount.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/ConnectedAccount.cs index 276fb07e9..c9aad6584 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Models/ConnectedAccount.cs +++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/ConnectedAccount.cs @@ -40,8 +40,8 @@ public partial class ConnectedAccount [Column("visibility")] public int Visibility { get; set; } - [Column("integrations")] - public string Integrations { get; set; } = null!; + [Column("integrations", TypeName = "character varying[]")] + public List Integrations { get; set; } = null!; [Column("metadata", TypeName = "jsonb")] public string? Metadata { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/Emoji.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/Emoji.cs index e8f925560..04b0ae03c 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Models/Emoji.cs +++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/Emoji.cs @@ -35,10 +35,10 @@ public partial class Emoji public bool RequireColons { get; set; } [Column("roles")] - public string Roles { get; set; } = null!; + public List Roles { get; set; } = null!; [Column("groups")] - public string? Groups { get; set; } + public List? Groups { get; set; } [ForeignKey("GuildId")] [InverseProperty("Emojis")] diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/Guild.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/Guild.cs index e93b49ad2..359caa846 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Models/Guild.cs +++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/Guild.cs @@ -34,8 +34,8 @@ public partial class Guild [Column("explicit_content_filter")] public int? ExplicitContentFilter { get; set; } - [Column("features")] - public string Features { get; set; } = null!; + [Column("features", TypeName = "character varying[]")] + public List Features { get; set; } = null!; [Column("primary_category_id")] public long? PrimaryCategoryId { get; set; } @@ -128,7 +128,7 @@ public partial class Guild public bool? PremiumProgressBarEnabled { get; set; } [Column("channel_ordering")] - public string ChannelOrdering { get; set; } = null!; + public List ChannelOrdering { get; set; } = null!; [Column("discovery_weight")] public int DiscoveryWeight { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/Member.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/Member.cs index d8311ca55..3d2a3e718 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Models/Member.cs +++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/Member.cs @@ -57,7 +57,7 @@ public partial class Member public string Bio { get; set; } = null!; [Column("theme_colors")] - public string? ThemeColors { get; set; } + public List? ThemeColors { get; set; } [Column("pronouns", TypeName = "character varying")] public string? Pronouns { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/TeamMember.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/TeamMember.cs index c626e859b..81ec04d73 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Models/TeamMember.cs +++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/TeamMember.cs @@ -16,8 +16,8 @@ public partial class TeamMember [Column("membership_state")] public int MembershipState { get; set; } - [Column("permissions")] - public string Permissions { get; set; } = null!; + [Column("permissions", TypeName = "character varying[]")] + public List Permissions { get; set; } = null!; [Column("team_id")] public long? TeamId { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Models/User.cs b/extra/admin-api/Models/Spacebar.Models.Db/Models/User.cs index ed0eaccbd..e1005db2e 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Models/User.cs +++ b/extra/admin-api/Models/Spacebar.Models.Db/Models/User.cs @@ -30,7 +30,7 @@ public partial class User public string? Banner { get; set; } [Column("theme_colors")] - public string? ThemeColors { get; set; } + public List? ThemeColors { get; set; } [Column("pronouns", TypeName = "character varying")] public string? Pronouns { get; set; } @@ -107,8 +107,8 @@ public partial class User [Column("data", TypeName = "jsonb")] public string Data { get; set; } = null!; - [Column("fingerprints")] - public string Fingerprints { get; set; } = null!; + [Column("fingerprints", TypeName = "character varying[]")] + public List Fingerprints { get; set; } = null!; [Column("settingsIndex")] public int? SettingsIndex { get; set; } @@ -117,7 +117,7 @@ public partial class User public bool WebauthnEnabled { get; set; } [Column("badge_ids")] - public string? BadgeIds { get; set; } + public List? BadgeIds { get; set; } [Column("avatar_decoration_data", TypeName = "jsonb")] public string? AvatarDecorationData { get; set; } diff --git a/extra/admin-api/Models/Spacebar.Models.Db/Spacebar.Models.Db.csproj b/extra/admin-api/Models/Spacebar.Models.Db/Spacebar.Models.Db.csproj index e987a369a..2d1dcaf5b 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/Spacebar.Models.Db.csproj +++ b/extra/admin-api/Models/Spacebar.Models.Db/Spacebar.Models.Db.csproj @@ -7,7 +7,8 @@ - + + diff --git a/extra/admin-api/Models/Spacebar.Models.Db/deps.json b/extra/admin-api/Models/Spacebar.Models.Db/deps.json index 79f44dd42..53b3a6624 100644 --- a/extra/admin-api/Models/Spacebar.Models.Db/deps.json +++ b/extra/admin-api/Models/Spacebar.Models.Db/deps.json @@ -1,59 +1,154 @@ [ + { + "pname": "Humanizer.Core", + "version": "2.14.1", + "hash": "sha256-EXvojddPu+9JKgOG9NSQgUTfWq1RpOYw7adxDPKDJ6o=" + }, + { + "pname": "Microsoft.Build.Framework", + "version": "17.11.31", + "hash": "sha256-YS4oASrmC5dmZrx5JPS7SfKmUpIJErlUpVDsU3VrfFE=" + }, + { + "pname": "Microsoft.Build.Framework", + "version": "18.0.2", + "hash": "sha256-fO31KAdDs2J0RUYD1ov9UB3ucsbALan7K0YdWW+yg7A=" + }, + { + "pname": "Microsoft.CodeAnalysis.Analyzers", + "version": "3.11.0", + "hash": "sha256-hQ2l6E6PO4m7i+ZsfFlEx+93UsLPo4IY3wDkNG11/Sw=" + }, + { + "pname": "Microsoft.CodeAnalysis.Common", + "version": "5.0.0", + "hash": "sha256-g4ALvBSNyHEmSb1l5TFtWW7zEkiRmhqLx4XWZu9sr2U=" + }, + { + "pname": "Microsoft.CodeAnalysis.CSharp", + "version": "5.0.0", + "hash": "sha256-ctBCkQGFpH/xT5rRE3xibu9YxPD108RuC4a4Z25koG8=" + }, + { + "pname": "Microsoft.CodeAnalysis.CSharp.Workspaces", + "version": "5.0.0", + "hash": "sha256-yWVcLt/f2CouOfFy966glGdtSFy+RcgrU1dd9UtlL/Q=" + }, + { + "pname": "Microsoft.CodeAnalysis.Workspaces.Common", + "version": "5.0.0", + "hash": "sha256-Bir5e1gEhgQQ6upQmVKQHAKLRfenAu60DAzNupNnZsQ=" + }, + { + "pname": "Microsoft.CodeAnalysis.Workspaces.MSBuild", + "version": "5.0.0", + "hash": "sha256-+58+iqTayTiE0pDaog1U8mjaDA8bNNDLA8gjCQZZudo=" + }, { "pname": "Microsoft.EntityFrameworkCore", "version": "10.0.4", "hash": "sha256-V3Vwl1MtVMRTPo7a9lAgs6UaeMnFV3eEsKnLyPaPMHA=" }, + { + "pname": "Microsoft.EntityFrameworkCore", + "version": "10.0.8", + "hash": "sha256-NvDbNeCIHHslXfHtoyxedtJ8BYcSjsvmKz0rc0jNhN0=" + }, { "pname": "Microsoft.EntityFrameworkCore.Abstractions", "version": "10.0.4", "hash": "sha256-so4y7Wrp/oWhQ7wd1rK9ha9GtPme1l5H8SrQz7sf8MQ=" }, + { + "pname": "Microsoft.EntityFrameworkCore.Abstractions", + "version": "10.0.8", + "hash": "sha256-vgjR3wT9QvR4LYgy4BaeIQlajW7KWhLAwHgXsyNxioc=" + }, { "pname": "Microsoft.EntityFrameworkCore.Analyzers", "version": "10.0.4", "hash": "sha256-Wed75M4RdQ7bCUWSc+q/0YqL6R5CrIZ2X0t/LpU7ZZA=" }, + { + "pname": "Microsoft.EntityFrameworkCore.Analyzers", + "version": "10.0.8", + "hash": "sha256-R2rH/R7Us1vbH4JWKvj364HKYXEe2b+7jXcI3C1d7v4=" + }, + { + "pname": "Microsoft.EntityFrameworkCore.Design", + "version": "10.0.8", + "hash": "sha256-QEb8xScQ6uimJwbqdaZA8WwL2pirmX80fi3BR6Swoeg=" + }, { "pname": "Microsoft.EntityFrameworkCore.Relational", "version": "10.0.4", "hash": "sha256-WwGoCwNxDXyqfBvUX9fGa/6X+yiDBuE7hf3csU78+Os=" }, + { + "pname": "Microsoft.EntityFrameworkCore.Relational", + "version": "10.0.8", + "hash": "sha256-dcvuQ0ga+TI2G6J31aOClH9hejp2/AftSJYNcRI3USo=" + }, { "pname": "Microsoft.Extensions.Caching.Abstractions", - "version": "10.0.4", - "hash": "sha256-/vLXWvT42HQAm/JLjWGeFo9AvLn/mu4nCNjabm+wABE=" + "version": "10.0.8", + "hash": "sha256-xn2gR3NHo4+XBZIqrHXo8QlYI7AnhA51gtlgSqrPpQ0=" }, { "pname": "Microsoft.Extensions.Caching.Memory", "version": "10.0.4", "hash": "sha256-+0sK/vSyB4KFC9kliECROfK1WaiWwlRrhLpi03pT+3w=" }, + { + "pname": "Microsoft.Extensions.Caching.Memory", + "version": "10.0.8", + "hash": "sha256-41uLtpgrA7S9WF3sIR9JVi90Kmmf6iy8mjmNTD9MQkU=" + }, { "pname": "Microsoft.Extensions.Configuration.Abstractions", - "version": "10.0.4", - "hash": "sha256-bvEQLGSOpJHKdPD6kd59IIi4x57lKapVMgOORtcjJPs=" + "version": "10.0.8", + "hash": "sha256-M0coNqsIolazd8E0jU8uf43X7Yw5Nf3+sXZQXX/xhq8=" }, { "pname": "Microsoft.Extensions.DependencyInjection", - "version": "10.0.4", - "hash": "sha256-hbpKNzN0KIszhlpM5iAT/V3B7QRs3FGTZI9Wq/cYc1A=" + "version": "10.0.8", + "hash": "sha256-eKex/vpm5A4o2WV6sJyjqKPydWhekJFO6wrH0V7RyBY=" + }, + { + "pname": "Microsoft.Extensions.DependencyInjection", + "version": "9.0.0", + "hash": "sha256-dAH52PPlTLn7X+1aI/7npdrDzMEFPMXRv4isV1a+14k=" }, { "pname": "Microsoft.Extensions.DependencyInjection.Abstractions", - "version": "10.0.0", - "hash": "sha256-9iodXP39YqgxomnOPOxd/mzbG0JfOSXzFoNU3omT2Ps=" + "version": "10.0.8", + "hash": "sha256-HV30fu+lF/GYkeVP+Yq/EU1FzgdMqwqlepCpvxUgugE=" }, { "pname": "Microsoft.Extensions.DependencyInjection.Abstractions", - "version": "10.0.4", - "hash": "sha256-0QhVYjk9Cxy6NFef9VKftGmscTZnvcD1bhBQoXz3mwA=" + "version": "9.0.0", + "hash": "sha256-CncVwkKZ5CsIG2O0+OM9qXuYXh3p6UGyueTHSLDVL+c=" + }, + { + "pname": "Microsoft.Extensions.DependencyModel", + "version": "10.0.8", + "hash": "sha256-YX986Og+47sJnNonmoZCqa54HCaZhJ8fJl45qeRaaUQ=" }, { "pname": "Microsoft.Extensions.Logging", "version": "10.0.4", "hash": "sha256-eneXBu83dGBiWMFabheGFPYiZJQ+WMewG6bTs2oJ7RA=" }, + { + "pname": "Microsoft.Extensions.Logging", + "version": "10.0.8", + "hash": "sha256-wcnZWJDQGe6iTd7SIvcbyZLO+Lyc3zCKWlYYP8ovA44=" + }, + { + "pname": "Microsoft.Extensions.Logging", + "version": "9.0.0", + "hash": "sha256-kR16c+N8nQrWeYLajqnXPg7RiXjZMSFLnKLEs4VfjcM=" + }, { "pname": "Microsoft.Extensions.Logging.Abstractions", "version": "10.0.0", @@ -61,18 +156,48 @@ }, { "pname": "Microsoft.Extensions.Logging.Abstractions", - "version": "10.0.4", - "hash": "sha256-dvBRBgEf4Bw9NW2J2XDlEeJw2TNhJ+6gV98dPE13/J0=" + "version": "10.0.8", + "hash": "sha256-VruWNhGycjxU2+BxiE++Aw2Tzv50lARcslDp66ImCDE=" + }, + { + "pname": "Microsoft.Extensions.Logging.Abstractions", + "version": "9.0.0", + "hash": "sha256-iBTs9twjWXFeERt4CErkIIcoJZU1jrd1RWCI8V5j7KU=" }, { "pname": "Microsoft.Extensions.Options", - "version": "10.0.4", - "hash": "sha256-ybyUtpSs/irdarkVjsGhqDcj0w8TNUgh0Kp0j3EVfIA=" + "version": "10.0.8", + "hash": "sha256-KHcgAMsOPgjK0ly34mAt3/1hPA4XDSltXUNrEjSNnh8=" + }, + { + "pname": "Microsoft.Extensions.Options", + "version": "9.0.0", + "hash": "sha256-DT5euAQY/ItB5LPI8WIp6Dnd0lSvBRP35vFkOXC68ck=" }, { "pname": "Microsoft.Extensions.Primitives", - "version": "10.0.4", - "hash": "sha256-ePpEFzrKQbEMY6Kh/xyxKHq6txNru62Vh4LVZO5Rrvg=" + "version": "10.0.8", + "hash": "sha256-LJFzI1nODfakvP3owQn8xwVKliRxIYs6nl19xAbxKOc=" + }, + { + "pname": "Microsoft.Extensions.Primitives", + "version": "9.0.0", + "hash": "sha256-ZNLusK1CRuq5BZYZMDqaz04PIKScE2Z7sS2tehU7EJs=" + }, + { + "pname": "Microsoft.VisualStudio.SolutionPersistence", + "version": "1.0.52", + "hash": "sha256-KZGPtOXe6Hv8RrkcsgoLKTRyaCScIpQEa2NhNB3iOXw=" + }, + { + "pname": "Mono.TextTemplating", + "version": "3.0.0", + "hash": "sha256-VlgGDvgNZb7MeBbIZ4DE2Nn/j2aD9k6XqNHnASUSDr0=" + }, + { + "pname": "Newtonsoft.Json", + "version": "13.0.3", + "hash": "sha256-hy/BieY4qxBWVVsDqqOPaLy1QobiIapkbrESm6v2PHc=" }, { "pname": "Npgsql", @@ -83,5 +208,40 @@ "pname": "Npgsql.EntityFrameworkCore.PostgreSQL", "version": "10.0.1", "hash": "sha256-G5WmWoc02gHTsdBLXESFQ5eMV+liwiO8YjzFKg4NDEk=" + }, + { + "pname": "System.CodeDom", + "version": "6.0.0", + "hash": "sha256-uPetUFZyHfxjScu5x4agjk9pIhbCkt5rG4Axj25npcQ=" + }, + { + "pname": "System.Composition", + "version": "9.0.0", + "hash": "sha256-FehOkQ2u1p8mQ0/wn3cZ+24HjhTLdck8VZYWA1CcgbM=" + }, + { + "pname": "System.Composition.AttributedModel", + "version": "9.0.0", + "hash": "sha256-a7y7H6zj+kmYkllNHA402DoVfY9IaqC3Ooys8Vzl24M=" + }, + { + "pname": "System.Composition.Convention", + "version": "9.0.0", + "hash": "sha256-tw4vE5JRQ60ubTZBbxoMPhtjOQCC3XoDFUH7NHO7o8U=" + }, + { + "pname": "System.Composition.Hosting", + "version": "9.0.0", + "hash": "sha256-oOxU+DPEEfMCuNLgW6wSkZp0JY5gYt44FJNnWt+967s=" + }, + { + "pname": "System.Composition.Runtime", + "version": "9.0.0", + "hash": "sha256-AyIe+di1TqwUBbSJ/sJ8Q8tzsnTN+VBdJw4K8xZz43s=" + }, + { + "pname": "System.Composition.TypedParts", + "version": "9.0.0", + "hash": "sha256-F5fpTUs3Rr7yP/NyIzr+Xn5NdTXXp8rrjBnF9UBBUog=" } ] diff --git a/extra/admin-api/Spacebar.AdminApi/Controllers/DiscoveryController.cs b/extra/admin-api/Spacebar.AdminApi/Controllers/DiscoveryController.cs index acc27c209..4c466acb4 100644 --- a/extra/admin-api/Spacebar.AdminApi/Controllers/DiscoveryController.cs +++ b/extra/admin-api/Spacebar.AdminApi/Controllers/DiscoveryController.cs @@ -29,7 +29,7 @@ public class GuildDiscoveryController( await foreach (var guild in discoverableGuilds.AsAsyncEnumerable()) { yield return new DiscoverableGuildModel() { Id = guild.Id, - Features = guild.Features.Split(",").ToList(), + Features = guild.Features, Banner = guild.Banner, DiscoveryExcluded = guild.DiscoveryExcluded, DiscoveryWeight = guild.DiscoveryWeight, @@ -38,7 +38,7 @@ public class GuildDiscoveryController( SystemChannelFlags = guild.SystemChannelFlags, AfkChannelId = guild.AfkChannelId, AfkTimeout = guild.AfkTimeout, - ChannelOrdering = guild.ChannelOrdering.Split(",").ToList(), + ChannelOrdering = guild.ChannelOrdering, DefaultMessageNotifications = guild.DefaultMessageNotifications, Description = guild.Description, DiscoverySplash = guild.DiscoverySplash, @@ -86,7 +86,7 @@ public class GuildDiscoveryController( var guild = await discoverableGuilds.SingleAsync(); return new DiscoverableGuildModel() { Id = guild.Id, - Features = guild.Features.Split(",").ToList(), + Features = guild.Features, Banner = guild.Banner, DiscoveryExcluded = guild.DiscoveryExcluded, DiscoveryWeight = guild.DiscoveryWeight, @@ -95,7 +95,7 @@ public class GuildDiscoveryController( SystemChannelFlags = guild.SystemChannelFlags, AfkChannelId = guild.AfkChannelId, AfkTimeout = guild.AfkTimeout, - ChannelOrdering = guild.ChannelOrdering.Split(",").ToList(), + ChannelOrdering = guild.ChannelOrdering, DefaultMessageNotifications = guild.DefaultMessageNotifications, Description = guild.Description, DiscoverySplash = guild.DiscoverySplash, @@ -152,7 +152,7 @@ public class GuildDiscoveryController( return new DiscoverableGuildModel() { Id = guild.Id, - Features = guild.Features.Split(",").ToList(), + Features = guild.Features, Banner = guild.Banner, DiscoveryExcluded = guild.DiscoveryExcluded, DiscoveryWeight = guild.DiscoveryWeight, @@ -161,7 +161,7 @@ public class GuildDiscoveryController( SystemChannelFlags = guild.SystemChannelFlags, AfkChannelId = guild.AfkChannelId, AfkTimeout = guild.AfkTimeout, - ChannelOrdering = guild.ChannelOrdering.Split(",").ToList(), + ChannelOrdering = guild.ChannelOrdering, DefaultMessageNotifications = guild.DefaultMessageNotifications, Description = guild.Description, DiscoverySplash = guild.DiscoverySplash, diff --git a/extra/admin-api/Spacebar.AdminApi/Controllers/UserController.cs b/extra/admin-api/Spacebar.AdminApi/Controllers/UserController.cs index 5b76c72db..51ec84e4f 100644 --- a/extra/admin-api/Spacebar.AdminApi/Controllers/UserController.cs +++ b/extra/admin-api/Spacebar.AdminApi/Controllers/UserController.cs @@ -1,3 +1,4 @@ +using System.Linq.Expressions; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Spacebar.AdminApi.Extensions; @@ -25,17 +26,17 @@ public class UserController( /// /// List of user objects [HttpGet] - public async IAsyncEnumerable Get() { + public async IAsyncEnumerable Get([FromQuery] string? orderBy, [FromQuery] bool ascending = false, [FromQuery] int? skip = null, [FromQuery] int? limit = null) { (await auth.GetCurrentUserAsync(Request)).GetRights().AssertHasAllRights(SpacebarRights.Rights.OPERATOR); - - var results = db.Users + var query = db.Users + .AsNoTracking() .Include(user => user.ApplicationBotUser) .Include(user => user.MessageAuthors) .Include(user => user.Sessions) .Include(user => user.Templates) .Include(user => user.VoiceStates) .Include(user => user.Guilds) - .AsAsyncEnumerable().Select(x => new UserModel { + .Select(x => new UserModel { Id = x.Id, Username = x.Username, Discriminator = x.Discriminator, @@ -74,7 +75,53 @@ public class UserController( OwnedGuildCount = x.Guilds.Count(g => g.OwnerId == x.Id) }); - await foreach (var user in results) { + if (!string.IsNullOrWhiteSpace(orderBy)) { + query = orderBy switch { + "id" => query.OrderByDescending(x => x.Id), + "username" => query.OrderByDescending(x => x.Username), + "discriminator" => query.OrderByDescending(x => x.Discriminator), + "avatar" => query.OrderByDescending(x => x.Avatar), + "accentColor" => query.OrderByDescending(x => x.AccentColor), + "banner" => query.OrderByDescending(x => x.Banner), + "themeColors" => query.OrderByDescending(x => x.ThemeColors), + "pronouns" => query.OrderByDescending(x => x.Pronouns), + "phone" => query.OrderByDescending(x => x.Phone), + "desktop" => query.OrderByDescending(x => x.Desktop), + "mobile" => query.OrderByDescending(x => x.Mobile), + "premium" => query.OrderByDescending(x => x.Premium), + "premiumType" => query.OrderByDescending(x => x.PremiumType), + "bot" => query.OrderByDescending(x => x.Bot), + "bio" => query.OrderByDescending(x => x.Bio), + "system" => query.OrderByDescending(x => x.System), + "nsfwAllowed" => query.OrderByDescending(x => x.NsfwAllowed), + "mfaEnabled" => query.OrderByDescending(x => x.MfaEnabled), + "webauthnEnabled" => query.OrderByDescending(x => x.WebauthnEnabled), + "createdAt" => query.OrderByDescending(x => x.CreatedAt), + "premiumSince" => query.OrderByDescending(x => x.PremiumSince), + "verified" => query.OrderByDescending(x => x.Verified), + "disabled" => query.OrderByDescending(x => x.Disabled), + "deleted" => query.OrderByDescending(x => x.Deleted), + "email" => query.OrderByDescending(x => x.Email), + "flags" => query.OrderByDescending(x => x.Flags), + "publicFlags" => query.OrderByDescending(x => x.PublicFlags), + "rights" => query.OrderByDescending(x => x.Rights), + "applicationBotUser" => query.OrderByDescending(x => x.ApplicationBotUser), + "connectedAccounts" => query.OrderByDescending(x => x.ConnectedAccounts), + "messageCount" => query.OrderByDescending(x => x.MessageCount), + "sessionCount" => query.OrderByDescending(x => x.SessionCount), + "templateCount" => query.OrderByDescending(x => x.TemplateCount), + "voiceStateCount" => query.OrderByDescending(x => x.VoiceStateCount), + "guildCount" => query.OrderByDescending(x => x.GuildCount), + "ownedGuildCount" => query.OrderByDescending(x => x.OwnedGuildCount), + _ => throw new Exception("orderBy is not oneOf(id)") + }; + if (ascending) query = query.Reverse(); + } + + if (skip.HasValue) query = query.Skip(skip.Value); + if (limit.HasValue) query = query.Take(limit.Value); + + await foreach (var user in query.AsAsyncEnumerable()) { yield return user; } } @@ -170,7 +217,7 @@ public class UserController( yield return new("STATS", new { total_messages = messages.Count(), total_channels = channels.Count, - messages_per_channel = channels.ToDictionary(c => c.ChannelId!, c => messages.Count(m => m.ChannelId == c.ChannelId)) + messages_per_channel = channels.ToDictionary(c => c.ChannelId!.ToString(), c => messages.Count(m => m.ChannelId == c.ChannelId)) }); if (messages.Any()) { var results = channels @@ -190,7 +237,7 @@ public class UserController( // [HttpGet("{id}/Dms")] // public async IEnumerable GetDmsAsync(string userId) { - // yield break; // TODO + // yield break; // TODO // } private async IAsyncEnumerable DeleteMessagesForChannel( @@ -206,15 +253,15 @@ public class UserController( var remaining = messagesInChannel; while (true) { var messageIds = _db.Database.SqlQuery($""" - DELETE FROM messages - WHERE id IN ( - SELECT id FROM messages - WHERE author_id = {authorId} - AND channel_id = {channelId} - AND guild_id = {guildId} - LIMIT {messageDeleteChunkSize} - ) RETURNING id; - """).ToList(); + DELETE FROM messages + WHERE id IN ( + SELECT id FROM messages + WHERE author_id = {authorId} + AND channel_id = {channelId} + AND guild_id = {guildId} + LIMIT {messageDeleteChunkSize} + ) RETURNING id; + """).ToList(); if (messageIds.Count == 0) { break; } diff --git a/extra/admin-api/Spacebar.AdminApi/Middleware/AuthenticationMiddleware.cs b/extra/admin-api/Spacebar.AdminApi/Middleware/AuthenticationMiddleware.cs index 484859edb..2ee476f6d 100644 --- a/extra/admin-api/Spacebar.AdminApi/Middleware/AuthenticationMiddleware.cs +++ b/extra/admin-api/Spacebar.AdminApi/Middleware/AuthenticationMiddleware.cs @@ -1,17 +1,28 @@ +using Microsoft.IdentityModel.Tokens; using Spacebar.Interop.Authentication; using Spacebar.Interop.Authentication.AspNetCore; using Spacebar.Models.Db.Models; namespace Spacebar.AdminApi.Middleware; -public class AuthenticationMiddleware(SpacebarAspNetAuthenticationService authService, SpacebarAuthenticationConfiguration config, RequestDelegate next) { +public class AuthenticationMiddleware( + ILogger logger, + SpacebarAspNetAuthenticationService authService, + SpacebarAuthenticationConfiguration config, + RequestDelegate next) { public async Task InvokeAsync(HttpContext context, IServiceProvider sp) { if (context.Request.Path.StartsWithSegments("/ping") || config.DisableAuthentication) { await next(context); return; } - var res = await authService.ValidateTokenAsync(context.Request); + TokenValidationResult? res = null; + try { + await authService.ValidateTokenAsync(context.Request); + } + catch (Exception e) { + logger.LogError("Failed to validate access token: {e}", e); + } if (!(res?.IsValid ?? false)) { context.Response.StatusCode = 401; @@ -19,16 +30,25 @@ public class AuthenticationMiddleware(SpacebarAspNetAuthenticationService authSe return; } - User user = await authService.GetCurrentUserAsync(context.Request); - if (user.Disabled) { - context.Response.StatusCode = 403; - await context.Response.WriteAsync("User is disabled"); - return; - } + try { + User user = await authService.GetCurrentUserAsync(context.Request); + if (user.Disabled) { + context.Response.StatusCode = 403; + await context.Response.WriteAsync("User is disabled"); + return; + } - if (user.Deleted) { - context.Response.StatusCode = 403; - await context.Response.WriteAsync("User is deleted"); + if (user.Deleted) { + context.Response.StatusCode = 403; + await context.Response.WriteAsync("User is deleted"); + return; + } + } + catch (Exception e) { + logger.LogError("Failed to query user: {e}", e); + + context.Response.StatusCode = 412; + await context.Response.WriteAsync("Failed to find user"); return; }