Admin API discovery stuff

This commit is contained in:
Rory&
2026-02-21 05:16:17 +01:00
parent 9c526d6cd4
commit 1dd40402af
4 changed files with 333 additions and 11 deletions

View File

@@ -0,0 +1,139 @@
using System.Text.Json.Serialization;
namespace Spacebar.Models.AdminApi;
public class DiscoverableGuildModel {
[JsonPropertyName("id")]
public string Id { get; set; } = null!;
[JsonPropertyName("afk_channel_id")]
public string? AfkChannelId { get; set; }
[JsonPropertyName("afk_timeout")]
public int? AfkTimeout { get; set; }
[JsonPropertyName("banner")]
public string? Banner { get; set; }
[JsonPropertyName("default_message_notifications")]
public int? DefaultMessageNotifications { get; set; }
[JsonPropertyName("description")]
public string? Description { get; set; }
[JsonPropertyName("discovery_splash")]
public string? DiscoverySplash { get; set; }
[JsonPropertyName("explicit_content_filter")]
public int? ExplicitContentFilter { get; set; }
[JsonPropertyName("features")]
public List<string> Features { get; set; }
[JsonPropertyName("primary_category_id")]
public string? PrimaryCategoryId { get; set; }
[JsonPropertyName("icon")]
public string? Icon { 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("presence_count")]
public int? PresenceCount { get; set; }
[JsonPropertyName("template_id")]
public string? TemplateId { get; set; }
[JsonPropertyName("mfa_level")]
public int? MfaLevel { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; } = null!;
[JsonPropertyName("owner_id")]
public string? OwnerId { get; set; }
[JsonPropertyName("preferred_locale")]
public string? PreferredLocale { get; set; }
[JsonPropertyName("premium_subscription_count")]
public int? PremiumSubscriptionCount { get; set; }
[JsonPropertyName("premium_tier")]
public int PremiumTier { get; set; }
[JsonPropertyName("public_updates_channel_id")]
public string? PublicUpdatesChannelId { get; set; }
[JsonPropertyName("rules_channel_id")]
public string? RulesChannelId { get; set; }
[JsonPropertyName("region")]
public string? Region { get; set; }
[JsonPropertyName("splash")]
public string? Splash { get; set; }
[JsonPropertyName("system_channel_id")]
public string? SystemChannelId { get; set; }
[JsonPropertyName("system_channel_flags")]
public int? SystemChannelFlags { get; set; }
[JsonPropertyName("unavailable")]
public bool Unavailable { get; set; }
[JsonPropertyName("verification_level")]
public int? VerificationLevel { get; set; }
[JsonPropertyName("welcome_screen")]
public string WelcomeScreen { get; set; } = null!;
[JsonPropertyName("widget_channel_id")]
public string? WidgetChannelId { get; set; }
[JsonPropertyName("widget_enabled")]
public bool WidgetEnabled { get; set; }
[JsonPropertyName("nsfw_level")]
public int? NsfwLevel { get; set; }
[JsonPropertyName("nsfw")]
public bool Nsfw { get; set; }
[JsonPropertyName("parent")]
public string? Parent { get; set; }
[JsonPropertyName("premium_progress_bar_enabled")]
public bool? PremiumProgressBarEnabled { get; set; }
[JsonPropertyName("channel_ordering")]
public List<string> ChannelOrdering { get; set; }
[JsonPropertyName("discovery_weight")]
public int DiscoveryWeight { get; set; }
[JsonPropertyName("discovery_excluded")]
public bool DiscoveryExcluded { get; set; }
}
public class DiscoverableGuildUpdateModel {
[JsonPropertyName("discovery_weight")]
public int? DiscoveryWeight { get; set; }
[JsonPropertyName("discovery_excluded")]
public bool? DiscoveryExcluded { get; set; }
}

View File

@@ -19,9 +19,180 @@ public class DiscoveryController(
ISpacebarReplication replication
) : ControllerBase {
[HttpGet]
public async Task GetDiscoverableGuilds() {
public async IAsyncEnumerable<DiscoverableGuildModel> GetDiscoverableGuilds(bool includeExcluded = false) {
(await auth.GetCurrentUserAsync(Request)).GetRights().AssertHasAllRights(SpacebarRights.Rights.OPERATOR);
// var discoverableGuilds = db.Guilds
// .Where(x=>x.)
var discoverableGuilds = db.Guilds
.AsNoTracking()
.Where(x => (!x.DiscoveryExcluded || includeExcluded) && x.Features.Contains("DISCOVERABLE"))
.OrderByDescending(x => x.DiscoveryWeight)
.ThenByDescending(x => x.MemberCount);
await foreach (var guild in discoverableGuilds.AsAsyncEnumerable()) {
yield return new DiscoverableGuildModel() {
Id = guild.Id,
Features = guild.Features.Split(",").ToList(),
Banner = guild.Banner,
DiscoveryExcluded = guild.DiscoveryExcluded,
DiscoveryWeight = guild.DiscoveryWeight,
MemberCount = guild.MemberCount,
Name = guild.Name,
SystemChannelFlags = guild.SystemChannelFlags,
AfkChannelId = guild.AfkChannelId,
AfkTimeout = guild.AfkTimeout,
ChannelOrdering = guild.ChannelOrdering.Split(",").ToList(),
DefaultMessageNotifications = guild.DefaultMessageNotifications,
Description = guild.Description,
DiscoverySplash = guild.DiscoverySplash,
ExplicitContentFilter = guild.ExplicitContentFilter,
Icon = guild.Icon,
Large = guild.Large,
MaxMembers = guild.MaxMembers,
MaxPresences = guild.MaxPresences,
MaxVideoChannelUsers = guild.MaxVideoChannelUsers,
MfaLevel = guild.MfaLevel,
Nsfw = guild.Nsfw,
NsfwLevel = guild.NsfwLevel,
OwnerId = guild.OwnerId,
Parent = guild.Parent,
PreferredLocale = guild.PreferredLocale,
PremiumProgressBarEnabled = guild.PremiumProgressBarEnabled,
PremiumTier = guild.PremiumTier,
PremiumSubscriptionCount = guild.PremiumSubscriptionCount,
PresenceCount = guild.PresenceCount,
PrimaryCategoryId = guild.PrimaryCategoryId,
PublicUpdatesChannelId = guild.PublicUpdatesChannelId,
Region = guild.Region,
RulesChannelId = guild.RulesChannelId,
Splash = guild.Splash,
SystemChannelId = guild.SystemChannelId,
TemplateId = guild.TemplateId,
Unavailable = guild.Unavailable,
VerificationLevel = guild.VerificationLevel,
WelcomeScreen = guild.WelcomeScreen,
WidgetChannelId = guild.WidgetChannelId,
WidgetEnabled = guild.WidgetEnabled
};
}
}
[HttpGet("{guildId}")]
public async Task<DiscoverableGuildModel> GetDiscoverableGuild(string guildId, bool includeExcluded = false) {
(await auth.GetCurrentUserAsync(Request)).GetRights().AssertHasAllRights(SpacebarRights.Rights.OPERATOR);
var discoverableGuilds = db.Guilds
.AsNoTracking()
.Where(x => x.Id == guildId)
.Where(x => (!x.DiscoveryExcluded || includeExcluded) && x.Features.Contains("DISCOVERABLE"))
.OrderByDescending(x => x.DiscoveryWeight)
.ThenByDescending(x => x.MemberCount);
var guild = await discoverableGuilds.SingleAsync();
return new DiscoverableGuildModel() {
Id = guild.Id,
Features = guild.Features.Split(",").ToList(),
Banner = guild.Banner,
DiscoveryExcluded = guild.DiscoveryExcluded,
DiscoveryWeight = guild.DiscoveryWeight,
MemberCount = guild.MemberCount,
Name = guild.Name,
SystemChannelFlags = guild.SystemChannelFlags,
AfkChannelId = guild.AfkChannelId,
AfkTimeout = guild.AfkTimeout,
ChannelOrdering = guild.ChannelOrdering.Split(",").ToList(),
DefaultMessageNotifications = guild.DefaultMessageNotifications,
Description = guild.Description,
DiscoverySplash = guild.DiscoverySplash,
ExplicitContentFilter = guild.ExplicitContentFilter,
Icon = guild.Icon,
Large = guild.Large,
MaxMembers = guild.MaxMembers,
MaxPresences = guild.MaxPresences,
MaxVideoChannelUsers = guild.MaxVideoChannelUsers,
MfaLevel = guild.MfaLevel,
Nsfw = guild.Nsfw,
NsfwLevel = guild.NsfwLevel,
OwnerId = guild.OwnerId,
Parent = guild.Parent,
PreferredLocale = guild.PreferredLocale,
PremiumProgressBarEnabled = guild.PremiumProgressBarEnabled,
PremiumTier = guild.PremiumTier,
PremiumSubscriptionCount = guild.PremiumSubscriptionCount,
PresenceCount = guild.PresenceCount,
PrimaryCategoryId = guild.PrimaryCategoryId,
PublicUpdatesChannelId = guild.PublicUpdatesChannelId,
Region = guild.Region,
RulesChannelId = guild.RulesChannelId,
Splash = guild.Splash,
SystemChannelId = guild.SystemChannelId,
TemplateId = guild.TemplateId,
Unavailable = guild.Unavailable,
VerificationLevel = guild.VerificationLevel,
WelcomeScreen = guild.WelcomeScreen,
WidgetChannelId = guild.WidgetChannelId,
WidgetEnabled = guild.WidgetEnabled
};
}
[HttpPatch("{guildId}")]
public async Task<DiscoverableGuildModel> UpdateDiscoverableGuild(string guildId, [FromBody] DiscoverableGuildUpdateModel guildUpdateModel, bool includeExcluded = false) {
(await auth.GetCurrentUserAsync(Request)).GetRights().AssertHasAllRights(SpacebarRights.Rights.OPERATOR);
var guild = await db.Guilds
.AsNoTracking()
.Where(x => x.Id == guildId)
.Where(x => (!x.DiscoveryExcluded || includeExcluded) && x.Features.Contains("DISCOVERABLE"))
.OrderByDescending(x => x.DiscoveryWeight)
.ThenByDescending(x => x.MemberCount)
.SingleAsync();
if (guildUpdateModel.DiscoveryExcluded != null)
guild.DiscoveryExcluded = guildUpdateModel.DiscoveryExcluded.Value;
if (guildUpdateModel.DiscoveryWeight != null)
guild.DiscoveryWeight = guildUpdateModel.DiscoveryWeight.Value;
db.Guilds.Update(guild);
await db.SaveChangesAsync();
return new DiscoverableGuildModel() {
Id = guild.Id,
Features = guild.Features.Split(",").ToList(),
Banner = guild.Banner,
DiscoveryExcluded = guild.DiscoveryExcluded,
DiscoveryWeight = guild.DiscoveryWeight,
MemberCount = guild.MemberCount,
Name = guild.Name,
SystemChannelFlags = guild.SystemChannelFlags,
AfkChannelId = guild.AfkChannelId,
AfkTimeout = guild.AfkTimeout,
ChannelOrdering = guild.ChannelOrdering.Split(",").ToList(),
DefaultMessageNotifications = guild.DefaultMessageNotifications,
Description = guild.Description,
DiscoverySplash = guild.DiscoverySplash,
ExplicitContentFilter = guild.ExplicitContentFilter,
Icon = guild.Icon,
Large = guild.Large,
MaxMembers = guild.MaxMembers,
MaxPresences = guild.MaxPresences,
MaxVideoChannelUsers = guild.MaxVideoChannelUsers,
MfaLevel = guild.MfaLevel,
Nsfw = guild.Nsfw,
NsfwLevel = guild.NsfwLevel,
OwnerId = guild.OwnerId,
Parent = guild.Parent,
PreferredLocale = guild.PreferredLocale,
PremiumProgressBarEnabled = guild.PremiumProgressBarEnabled,
PremiumTier = guild.PremiumTier,
PremiumSubscriptionCount = guild.PremiumSubscriptionCount,
PresenceCount = guild.PresenceCount,
PrimaryCategoryId = guild.PrimaryCategoryId,
PublicUpdatesChannelId = guild.PublicUpdatesChannelId,
Region = guild.Region,
RulesChannelId = guild.RulesChannelId,
Splash = guild.Splash,
SystemChannelId = guild.SystemChannelId,
TemplateId = guild.TemplateId,
Unavailable = guild.Unavailable,
VerificationLevel = guild.VerificationLevel,
WelcomeScreen = guild.WelcomeScreen,
WidgetChannelId = guild.WidgetChannelId,
WidgetEnabled = guild.WidgetEnabled
};
}
}

View File

@@ -1,4 +1,4 @@
@Spacebar.AdminApi_HostAddress = http://localhost:5112
@SpacebarAdminApi_HostAddress = http://localhost:5112
POST {{Spacebar.AdminApi_HostAddress}}/_spacebar/admin/guilds/1473141782615941382/force_join
Content-Type: application/json
@@ -10,3 +10,10 @@ Accept: application/json
}
###
GET {{SpacebarAdminApi_HostAddress}}/_spacebar/admin/discovery
Content-Type: application/json
Accept: application/json
Authorization: null null
###

View File

@@ -16,7 +16,8 @@ if (args.Length > 0) {
Console.WriteLine($"==> Updating dependencies for {outs.Length} projects...");
foreach (var outp in outs) {
var ss = new SemaphoreSlim(1, 1);
var tasks = outs.Select(outp => Task.Run(async () => {
Console.WriteLine(ConsoleUtils.ColoredString($" ==> Updating {outp}...", 0x80, 0x80, 0xff));
Console.Write(ConsoleUtils.ColoredString($" ==> Getting project root directory... ", 0x80, 0xff, 0xff));
var rootDir = JsonSerializer.Deserialize<string>(Util.GetCommandOutputSync("nix", $"eval --json .#packages.x86_64-linux.{outp}.srcRoot", silent: true, stderr: false)).Split("/extra/admin-api/",2)[1];
@@ -27,18 +28,22 @@ foreach (var outp in outs) {
Console.WriteLine(ConsoleUtils.ColoredString($" ==> {nugetDepsFilePath} exists: {File.Exists(nugetDepsFilePath)}", 0x80, 0xff, 0xff));
if (!File.Exists(nugetDepsFilePath)) {
Console.WriteLine(ConsoleUtils.ColoredString($" ==> No NuGet deps file, skipping!", 0xff, 0x80, 0x80));
continue;
return;
}
Console.WriteLine(ConsoleUtils.ColoredString($" ==> Building fetch-deps script...", 0x80, 0xff, 0x80));
Util.RunCommandSync("nix", $"build .#{outp}.passthru.fetch-deps");
var fname = $"./update-deps-{outp}";
Console.WriteLine(ConsoleUtils.ColoredString($" ==> Building fetch-deps script {fname}...", 0x80, 0xff, 0x80));
Util.RunCommandSync("nix", $"build .#{outp}.passthru.fetch-deps --out-link {fname}");
Console.WriteLine(ConsoleUtils.ColoredString($" ==> Running fetch-deps script...", 0x80, 0xff, 0x80));
Util.RunCommandSync("./result", nugetDepsFilePath);
Util.RunCommandSync(fname, nugetDepsFilePath);
var deps = JsonSerializer.Deserialize<object[]>(File.ReadAllText(nugetDepsFilePath));
var deps = JsonSerializer.Deserialize<object[]>(await File.ReadAllTextAsync(nugetDepsFilePath));
Console.WriteLine(ConsoleUtils.ColoredString($" ==> Locked {deps.Length} dependencies...", (byte)(deps.Length == 0 ? 0xff : 0x80), (byte)(deps.Length == 0 ? 0x80 : 0xff), 0x80));
File.Delete(fname);
// await Task.Delay(250);
}
})).ToList();
await Task.WhenAll(tasks);