side tangent: update C# DB model, fix admin api auth

This commit is contained in:
Rory&
2026-05-25 09:15:06 +02:00
parent 6d0564ed37
commit b05519d394
17 changed files with 307 additions and 77 deletions
@@ -53,7 +53,7 @@ public class SpacebarAuthenticationService(ILogger<SpacebarAuthenticationService
async () => {
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<SpacebarAuthenticationService
async () => {
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);
}
@@ -120,8 +120,8 @@ public class DiscoverableGuildModel {
[JsonPropertyName("premium_progress_bar_enabled")]
public bool? PremiumProgressBarEnabled { get; set; }
[JsonPropertyName("channel_ordering")]
public List<string> ChannelOrdering { get; set; }
[JsonPropertyName("channel_ordering"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public List<long> ChannelOrdering { get; set; }
[JsonPropertyName("discovery_weight")]
public int DiscoveryWeight { get; set; }
@@ -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<string> 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<long> ChannelOrdering { get; set; } = null!;
public int ChannelCount { get; set; }
public int RoleCount { get; set; }
@@ -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<int>? ThemeColors { get; set; }
public string? Pronouns { get; set; }
public string? Phone { get; set; }
public bool Desktop { get; set; }
@@ -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<string>? 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<string>? Tags { get; set; }
[Column("cover_image", TypeName = "character varying")]
public string? CoverImage { get; set; }
@@ -20,10 +20,10 @@ public partial class AutomodRule
public int EventType { get; set; }
[Column("exempt_channels")]
public string ExemptChannels { get; set; } = null!;
public List<long> ExemptChannels { get; set; } = null!;
[Column("exempt_roles")]
public string ExemptRoles { get; set; } = null!;
public List<long> ExemptRoles { get; set; } = null!;
[Column("guild_id")]
public long GuildId { get; set; }
@@ -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<string> Integrations { get; set; } = null!;
[Column("metadata", TypeName = "jsonb")]
public string? Metadata { get; set; }
@@ -35,10 +35,10 @@ public partial class Emoji
public bool RequireColons { get; set; }
[Column("roles")]
public string Roles { get; set; } = null!;
public List<long> Roles { get; set; } = null!;
[Column("groups")]
public string? Groups { get; set; }
public List<long>? Groups { get; set; }
[ForeignKey("GuildId")]
[InverseProperty("Emojis")]
@@ -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<string> 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<long> ChannelOrdering { get; set; } = null!;
[Column("discovery_weight")]
public int DiscoveryWeight { get; set; }
@@ -57,7 +57,7 @@ public partial class Member
public string Bio { get; set; } = null!;
[Column("theme_colors")]
public string? ThemeColors { get; set; }
public List<int>? ThemeColors { get; set; }
[Column("pronouns", TypeName = "character varying")]
public string? Pronouns { get; set; }
@@ -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<string> Permissions { get; set; } = null!;
[Column("team_id")]
public long? TeamId { get; set; }
@@ -30,7 +30,7 @@ public partial class User
public string? Banner { get; set; }
[Column("theme_colors")]
public string? ThemeColors { get; set; }
public List<int>? 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<string> 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<long>? BadgeIds { get; set; }
[Column("avatar_decoration_data", TypeName = "jsonb")]
public string? AvatarDecorationData { get; set; }
@@ -7,7 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="*" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="*" />
</ItemGroup>
</Project>
@@ -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="
}
]
@@ -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,
@@ -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(
/// </summary>
/// <returns>List of user objects</returns>
[HttpGet]
public async IAsyncEnumerable<UserModel> Get() {
public async IAsyncEnumerable<UserModel> 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<object> GetDmsAsync(string userId) {
// yield break; // TODO
// yield break; // TODO
// }
private async IAsyncEnumerable<AsyncActionResult> DeleteMessagesForChannel(
@@ -206,15 +253,15 @@ public class UserController(
var remaining = messagesInChannel;
while (true) {
var messageIds = _db.Database.SqlQuery<long>($"""
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;
}
@@ -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<AuthenticationMiddleware> 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;
}