feat: add premium management admin commands

This commit is contained in:
Iris System 2025-12-27 15:04:31 +13:00
parent bd5b5c03fe
commit a6941cea08
3 changed files with 93 additions and 0 deletions

View file

@ -182,6 +182,8 @@ public partial class CommandTree
await ctx.Execute<Admin>(Admin, a => a.SystemRecover(ctx));
else if (ctx.Match("sd", "systemdelete"))
await ctx.Execute<Admin>(Admin, a => a.SystemDelete(ctx));
else if (ctx.Match("pe", "premiumexpiry", "premium"))
await ctx.Execute<Admin>(Admin, a => a.PremiumExpiry(ctx));
else if (ctx.Match("sendmsg", "sendmessage"))
await ctx.Execute<Admin>(Admin, a => a.SendAdminMessage(ctx));
else if (ctx.Match("al", "abuselog"))

View file

@ -2,6 +2,8 @@ using System.Text.RegularExpressions;
using Humanizer;
using Dapper;
using NodaTime;
using NodaTime.Text;
using SqlKata;
using Myriad.Builders;
@ -79,6 +81,16 @@ public class Admin
var groupCount = await ctx.Repository.GetSystemGroupCount(system.Id);
eb.Field(new Embed.Field("Group limit", $"{groupLimit} {UntilLimit(groupCount, groupLimit)}", true));
var premiumEntitlement = "none";
if (config.PremiumLifetime)
premiumEntitlement = $"<:lifetime_premium:{_botConfig.PremiumLifetimeEmoji}> **lifetime**";
else if (config.PremiumUntil != null)
if (SystemClock.Instance.GetCurrentInstant() < config.PremiumUntil!)
premiumEntitlement = $"<:premium_subscriber:{_botConfig.PremiumSubscriberEmoji}> <t:{config.PremiumUntil?.ToUnixTimeSeconds()}> <t:{config.PremiumUntil?.ToUnixTimeSeconds()}:R>";
else
premiumEntitlement = $"Expired! <t:{config.PremiumUntil?.ToUnixTimeSeconds()}> <t:{config.PremiumUntil?.ToUnixTimeSeconds()}:R>";
eb.Field(new Embed.Field("Premium entitlement", premiumEntitlement, false));
return eb.Build();
}
@ -396,6 +408,75 @@ public class Admin
await ctx.Reply($"{Emojis.Success} System deletion succesful.");
}
public async Task PremiumExpiry(Context ctx)
{
ctx.AssertBotAdmin();
var target = await ctx.MatchSystem();
if (target == null)
throw new PKError("Unknown system.");
await ctx.Reply(null, await CreateEmbed(ctx, target));
if (!ctx.HasNext())
return;
if (ctx.Match("lifetime", "staff"))
{
if (!await ctx.PromptYesNo($"Grant system `{target.Hid}` lifetime premium?", "Grant"))
throw new PKError("Premium entitlement change cancelled.");
await ctx.Repository.UpdateSystemConfig(target.Id, new SystemConfigPatch
{
PremiumLifetime = true,
PremiumUntil = null,
});
await ctx.Reply($"{Emojis.Success} Premium entitlement changed.");
}
else if (ctx.Match("none", "clear"))
{
if (!await ctx.PromptYesNo($"Clear premium entitlements for system `{target.Hid}`?", "Clear"))
throw new PKError("Premium entitlement change cancelled.");
await ctx.Repository.UpdateSystemConfig(target.Id, new SystemConfigPatch
{
PremiumLifetime = false,
PremiumUntil = null,
});
await ctx.Reply($"{Emojis.Success} Premium entitlement changed.");
}
else
{
var timeToMove = ctx.RemainderOrNull() ??
throw new PKSyntaxError("Must pass a date/time to set premium expiry to.");
Instant? time = null;
// DateUtils.ParseDateTime expects periods to be in the past, so we have to do
// this explicitly here...
var duration = DateUtils.ParsePeriod(timeToMove);
if (duration != null)
{
time = SystemClock.Instance.GetCurrentInstant() + duration;
}
else
{
var result = DateUtils.ParseDateTime(timeToMove, false);
if (result == null) throw Errors.InvalidDateTime(timeToMove);
time = result.Value.ToInstant();
}
if (!await ctx.PromptYesNo($"Change premium expiry for system `{target.Hid}` to <t:{time?.ToUnixTimeSeconds()}>?", "Change"))
throw new PKError("Premium entitlement change cancelled.");
await ctx.Repository.UpdateSystemConfig(target.Id, new SystemConfigPatch
{
PremiumLifetime = false,
PremiumUntil = time,
});
await ctx.Reply($"{Emojis.Success} Premium entitlement changed.");
}
}
public async Task AbuseLogCreate(Context ctx)
{
var denyBotUsage = ctx.MatchFlag("deny", "deny-bot-usage");

View file

@ -26,6 +26,8 @@ public class SystemConfigPatch: PatchObject
public Partial<string?> NameFormat { get; set; }
public Partial<SystemConfig.HidPadFormat> HidListPadding { get; set; }
public Partial<SystemConfig.ProxySwitchAction> ProxySwitch { get; set; }
public Partial<bool> PremiumLifetime { get; set; }
public Partial<Instant?> PremiumUntil { get; set; }
public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper
.With("ui_tz", UiTz)
@ -45,6 +47,8 @@ public class SystemConfigPatch: PatchObject
.With("card_show_color_hex", CardShowColorHex)
.With("proxy_switch", ProxySwitch)
.With("name_format", NameFormat)
.With("premium_lifetime", PremiumLifetime)
.With("premium_until", PremiumUntil)
);
public new void AssertIsValid()
@ -118,6 +122,12 @@ public class SystemConfigPatch: PatchObject
if (NameFormat.IsPresent)
o.Add("name_format", NameFormat.Value);
if (PremiumLifetime.IsPresent)
o.Add("premium_lifetime", PremiumLifetime.Value);
if (PremiumUntil.IsPresent)
o.Add("premium_until", PremiumUntil.Value?.FormatExport());
return o;
}