Add a few utility admin commands
Signed-off-by: Ske <voltasalt@gmail.com>
This commit is contained in:
parent
af5de7c892
commit
8740230c3d
@ -1,14 +1,28 @@
|
|||||||
using Myriad.Rest.Types;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
using Myriad.Rest.Types;
|
||||||
|
using Myriad.Utils;
|
||||||
|
|
||||||
namespace Myriad.Types
|
namespace Myriad.Types
|
||||||
{
|
{
|
||||||
public record InteractionApplicationCommandCallbackData
|
public record InteractionApplicationCommandCallbackData
|
||||||
{
|
{
|
||||||
public bool? Tts { get; init; }
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||||
public string? Content { get; init; }
|
public Optional<bool?> Tts { get; init; }
|
||||||
public Embed[]? Embeds { get; init; }
|
|
||||||
public AllowedMentions? AllowedMentions { get; init; }
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||||
public Message.MessageFlags Flags { get; init; }
|
public Optional<string?> Content { get; init; }
|
||||||
public MessageComponent[]? Components { get; init; }
|
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||||
|
public Optional<Embed[]?> Embeds { get; init; }
|
||||||
|
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||||
|
public Optional<AllowedMentions?> AllowedMentions { get; init; }
|
||||||
|
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||||
|
public Optional<Message.MessageFlags> Flags { get; init; }
|
||||||
|
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||||
|
public Optional<MessageComponent[]?> Components { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,7 +14,6 @@ using Myriad.Cache;
|
|||||||
using Myriad.Extensions;
|
using Myriad.Extensions;
|
||||||
using Myriad.Gateway;
|
using Myriad.Gateway;
|
||||||
using Myriad.Rest;
|
using Myriad.Rest;
|
||||||
using Myriad.Rest.Exceptions;
|
|
||||||
using Myriad.Types;
|
using Myriad.Types;
|
||||||
|
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
|
@ -13,5 +13,7 @@ namespace PluralKit.Bot
|
|||||||
public string[] Prefixes { get; set; }
|
public string[] Prefixes { get; set; }
|
||||||
|
|
||||||
public int? MaxShardConcurrency { get; set; }
|
public int? MaxShardConcurrency { get; set; }
|
||||||
|
|
||||||
|
public ulong? AdminRole { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
128
PluralKit.Bot/Commands/Admin.cs
Normal file
128
PluralKit.Bot/Commands/Admin.cs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using PluralKit.Bot.Interactive;
|
||||||
|
using PluralKit.Core;
|
||||||
|
|
||||||
|
namespace PluralKit.Bot
|
||||||
|
{
|
||||||
|
public class Admin
|
||||||
|
{
|
||||||
|
private readonly BotConfig _botConfig;
|
||||||
|
private readonly IDatabase _db;
|
||||||
|
private readonly ModelRepository _repo;
|
||||||
|
|
||||||
|
public Admin(BotConfig botConfig, IDatabase db, ModelRepository repo)
|
||||||
|
{
|
||||||
|
_botConfig = botConfig;
|
||||||
|
_db = db;
|
||||||
|
_repo = repo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateSystemId(Context ctx)
|
||||||
|
{
|
||||||
|
AssertBotAdmin(ctx);
|
||||||
|
|
||||||
|
var target = await ctx.MatchSystem();
|
||||||
|
if (target == null)
|
||||||
|
throw new PKError("Unknown system.");
|
||||||
|
|
||||||
|
var newHid = ctx.PopArgument();
|
||||||
|
if (!Regex.IsMatch(newHid, "^[a-z]{5}$"))
|
||||||
|
throw new PKError($"Invalid new system ID `{newHid}`.");
|
||||||
|
|
||||||
|
var existingSystem = await _db.Execute(c => _repo.GetSystemByHid(c, newHid));
|
||||||
|
if (existingSystem != null)
|
||||||
|
throw new PKError($"Another system already exists with ID `{newHid}`.");
|
||||||
|
|
||||||
|
var prompt = new YesNoPrompt(ctx)
|
||||||
|
{
|
||||||
|
Message = $"Change system ID of `{target.Hid}` to `{newHid}`?",
|
||||||
|
AcceptLabel = "Change"
|
||||||
|
};
|
||||||
|
await prompt.Run();
|
||||||
|
|
||||||
|
await _db.Execute(c => _repo.UpdateSystem(c, target.Id, new SystemPatch {Hid = newHid}));
|
||||||
|
await ctx.Reply($"{Emojis.Success} System ID updated (`{target.Hid}` -> `{newHid}`).");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateMemberId(Context ctx)
|
||||||
|
{
|
||||||
|
AssertBotAdmin(ctx);
|
||||||
|
|
||||||
|
var target = await ctx.MatchMember();
|
||||||
|
if (target == null)
|
||||||
|
throw new PKError("Unknown member.");
|
||||||
|
|
||||||
|
var newHid = ctx.PopArgument();
|
||||||
|
if (!Regex.IsMatch(newHid, "^[a-z]{5}$"))
|
||||||
|
throw new PKError($"Invalid new member ID `{newHid}`.");
|
||||||
|
|
||||||
|
var existingMember = await _db.Execute(c => _repo.GetMemberByHid(c, newHid));
|
||||||
|
if (existingMember != null)
|
||||||
|
throw new PKError($"Another member already exists with ID `{newHid}`.");
|
||||||
|
|
||||||
|
var prompt = new YesNoPrompt(ctx)
|
||||||
|
{
|
||||||
|
Message = $"Change member ID of **{target.NameFor(LookupContext.ByNonOwner)}** (`{target.Hid}`) to `{newHid}`?",
|
||||||
|
AcceptLabel = "Change"
|
||||||
|
};
|
||||||
|
await prompt.Run();
|
||||||
|
|
||||||
|
if (prompt.Result != true)
|
||||||
|
throw new PKError("ID change cancelled.");
|
||||||
|
|
||||||
|
await _db.Execute(c => _repo.UpdateMember(c, target.Id, new MemberPatch {Hid = newHid}));
|
||||||
|
await ctx.Reply($"{Emojis.Success} Member ID updated (`{target.Hid}` -> `{newHid}`).");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SystemMemberLimit(Context ctx)
|
||||||
|
{
|
||||||
|
AssertBotAdmin(ctx);
|
||||||
|
|
||||||
|
var target = await ctx.MatchSystem();
|
||||||
|
if (target == null)
|
||||||
|
throw new PKError("Unknown system.");
|
||||||
|
|
||||||
|
var currentLimit = target.MemberLimitOverride ?? Limits.MaxMemberCount;
|
||||||
|
if (!ctx.HasNext())
|
||||||
|
{
|
||||||
|
await ctx.Reply($"Current member limit is **{currentLimit}** members.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newLimitStr = ctx.PopArgument();
|
||||||
|
if (!int.TryParse(newLimitStr, out var newLimit))
|
||||||
|
throw new PKError($"Couldn't parse `{newLimitStr}` as number.");
|
||||||
|
|
||||||
|
var prompt = new YesNoPrompt(ctx)
|
||||||
|
{
|
||||||
|
Message = $"Update member limit from **{currentLimit}** to **{newLimit}**?",
|
||||||
|
AcceptLabel = "Update"
|
||||||
|
};
|
||||||
|
await prompt.Run();
|
||||||
|
|
||||||
|
if (prompt.Result != true)
|
||||||
|
throw new PKError("Member limit change cancelled.");
|
||||||
|
|
||||||
|
await using var conn = await _db.Obtain();
|
||||||
|
await _repo.UpdateSystem(conn, target.Id, new SystemPatch
|
||||||
|
{
|
||||||
|
MemberLimitOverride = newLimit
|
||||||
|
});
|
||||||
|
await ctx.Reply($"{Emojis.Success} Member limit updated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssertBotAdmin(Context ctx)
|
||||||
|
{
|
||||||
|
if (!IsBotAdmin(ctx))
|
||||||
|
throw new PKError("This command is only usable by bot admins.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsBotAdmin(Context ctx)
|
||||||
|
{
|
||||||
|
return _botConfig.AdminRole != null && ctx.Member.Roles.Contains(_botConfig.AdminRole.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -90,6 +90,7 @@ namespace PluralKit.Bot
|
|||||||
public static Command BlacklistRemove = new Command("blacklist remove", "blacklist remove all|<channel> [channel 2] [channel 3...]", "Removes certain channels from the proxy blacklist");
|
public static Command BlacklistRemove = new Command("blacklist remove", "blacklist remove all|<channel> [channel 2] [channel 3...]", "Removes certain channels from the proxy blacklist");
|
||||||
public static Command Invite = new Command("invite", "invite", "Gets a link to invite PluralKit to other servers");
|
public static Command Invite = new Command("invite", "invite", "Gets a link to invite PluralKit to other servers");
|
||||||
public static Command PermCheck = new Command("permcheck", "permcheck <guild>", "Checks whether a server's permission setup is correct");
|
public static Command PermCheck = new Command("permcheck", "permcheck <guild>", "Checks whether a server's permission setup is correct");
|
||||||
|
public static Command Admin = new Command("admin", "admin", "Super secret admin commands (sshhhh)");
|
||||||
|
|
||||||
public static Command[] SystemCommands = {
|
public static Command[] SystemCommands = {
|
||||||
SystemInfo, SystemNew, SystemRename, SystemTag, SystemDesc, SystemAvatar, SystemColor, SystemDelete, SystemTimezone,
|
SystemInfo, SystemNew, SystemRename, SystemTag, SystemDesc, SystemAvatar, SystemColor, SystemDelete, SystemTimezone,
|
||||||
@ -197,6 +198,8 @@ namespace PluralKit.Bot
|
|||||||
if (ctx.Match("stats")) return ctx.Execute<Misc>(null, m => m.Stats(ctx));
|
if (ctx.Match("stats")) return ctx.Execute<Misc>(null, m => m.Stats(ctx));
|
||||||
if (ctx.Match("permcheck"))
|
if (ctx.Match("permcheck"))
|
||||||
return ctx.Execute<Misc>(PermCheck, m => m.PermCheckGuild(ctx));
|
return ctx.Execute<Misc>(PermCheck, m => m.PermCheckGuild(ctx));
|
||||||
|
if (ctx.Match("admin"))
|
||||||
|
return HandleAdminCommand(ctx);
|
||||||
if (ctx.Match("random", "r"))
|
if (ctx.Match("random", "r"))
|
||||||
if (ctx.Match("group", "g") || ctx.MatchFlag("group", "g"))
|
if (ctx.Match("group", "g") || ctx.MatchFlag("group", "g"))
|
||||||
return ctx.Execute<Random>(GroupRandom, r => r.Group(ctx));
|
return ctx.Execute<Random>(GroupRandom, r => r.Group(ctx));
|
||||||
@ -208,6 +211,18 @@ namespace PluralKit.Bot
|
|||||||
$"{Emojis.Error} Unknown command {ctx.PeekArgument().AsCode()}. For a list of possible commands, see <https://pluralkit.me/commands>.");
|
$"{Emojis.Error} Unknown command {ctx.PeekArgument().AsCode()}. For a list of possible commands, see <https://pluralkit.me/commands>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task HandleAdminCommand(Context ctx)
|
||||||
|
{
|
||||||
|
if (ctx.Match("usid", "updatesystemid"))
|
||||||
|
await ctx.Execute<Admin>(Admin, a => a.UpdateSystemId(ctx));
|
||||||
|
else if (ctx.Match("umid", "updatememberid"))
|
||||||
|
await ctx.Execute<Admin>(Admin, a => a.UpdateMemberId(ctx));
|
||||||
|
else if (ctx.Match("uml", "updatememberlimit"))
|
||||||
|
await ctx.Execute<Admin>(Admin, a => a.SystemMemberLimit(ctx));
|
||||||
|
else
|
||||||
|
await ctx.Reply($"{Emojis.Error} Unknown command.");
|
||||||
|
}
|
||||||
|
|
||||||
private async Task HandleSystemCommand(Context ctx)
|
private async Task HandleSystemCommand(Context ctx)
|
||||||
{
|
{
|
||||||
// If we have no parameters, default to self-target
|
// If we have no parameters, default to self-target
|
||||||
|
@ -43,13 +43,11 @@ namespace PluralKit.Bot.Interactive
|
|||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task Update(InteractionContext ctx, string? content = null, Embed? embed = null)
|
protected async Task Update(InteractionContext ctx)
|
||||||
{
|
{
|
||||||
await ctx.Respond(InteractionResponse.ResponseType.UpdateMessage,
|
await ctx.Respond(InteractionResponse.ResponseType.UpdateMessage,
|
||||||
new InteractionApplicationCommandCallbackData
|
new InteractionApplicationCommandCallbackData
|
||||||
{
|
{
|
||||||
Content = content,
|
|
||||||
Embeds = embed != null ? new[] { embed } : null,
|
|
||||||
Components = GetComponents()
|
Components = GetComponents()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ namespace PluralKit.Bot
|
|||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
builder.RegisterType<CommandTree>().AsSelf();
|
builder.RegisterType<CommandTree>().AsSelf();
|
||||||
|
builder.RegisterType<Admin>().AsSelf();
|
||||||
builder.RegisterType<Autoproxy>().AsSelf();
|
builder.RegisterType<Autoproxy>().AsSelf();
|
||||||
builder.RegisterType<Fun>().AsSelf();
|
builder.RegisterType<Fun>().AsSelf();
|
||||||
builder.RegisterType<Groups>().AsSelf();
|
builder.RegisterType<Groups>().AsSelf();
|
||||||
|
@ -8,6 +8,7 @@ namespace PluralKit.Core
|
|||||||
public class MemberPatch: PatchObject
|
public class MemberPatch: PatchObject
|
||||||
{
|
{
|
||||||
public Partial<string> Name { get; set; }
|
public Partial<string> Name { get; set; }
|
||||||
|
public Partial<string> Hid { get; set; }
|
||||||
public Partial<string?> DisplayName { get; set; }
|
public Partial<string?> DisplayName { get; set; }
|
||||||
public Partial<string?> AvatarUrl { get; set; }
|
public Partial<string?> AvatarUrl { get; set; }
|
||||||
public Partial<string?> Color { get; set; }
|
public Partial<string?> Color { get; set; }
|
||||||
@ -28,6 +29,7 @@ namespace PluralKit.Core
|
|||||||
|
|
||||||
public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b
|
public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b
|
||||||
.With("name", Name)
|
.With("name", Name)
|
||||||
|
.With("hid", Hid)
|
||||||
.With("display_name", DisplayName)
|
.With("display_name", DisplayName)
|
||||||
.With("avatar_url", AvatarUrl)
|
.With("avatar_url", AvatarUrl)
|
||||||
.With("color", Color)
|
.With("color", Color)
|
||||||
|
@ -6,6 +6,7 @@ namespace PluralKit.Core
|
|||||||
public class SystemPatch: PatchObject
|
public class SystemPatch: PatchObject
|
||||||
{
|
{
|
||||||
public Partial<string?> Name { get; set; }
|
public Partial<string?> Name { get; set; }
|
||||||
|
public Partial<string?> Hid { get; set; }
|
||||||
public Partial<string?> Description { get; set; }
|
public Partial<string?> Description { get; set; }
|
||||||
public Partial<string?> Tag { get; set; }
|
public Partial<string?> Tag { get; set; }
|
||||||
public Partial<string?> AvatarUrl { get; set; }
|
public Partial<string?> AvatarUrl { get; set; }
|
||||||
@ -19,9 +20,12 @@ namespace PluralKit.Core
|
|||||||
public Partial<PrivacyLevel> FrontHistoryPrivacy { get; set; }
|
public Partial<PrivacyLevel> FrontHistoryPrivacy { get; set; }
|
||||||
public Partial<bool> PingsEnabled { get; set; }
|
public Partial<bool> PingsEnabled { get; set; }
|
||||||
public Partial<int?> LatchTimeout { get; set; }
|
public Partial<int?> LatchTimeout { get; set; }
|
||||||
|
public Partial<int?> MemberLimitOverride { get; set; }
|
||||||
|
public Partial<int?> GroupLimitOverride { get; set; }
|
||||||
|
|
||||||
public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b
|
public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b
|
||||||
.With("name", Name)
|
.With("name", Name)
|
||||||
|
.With("hid", Hid)
|
||||||
.With("description", Description)
|
.With("description", Description)
|
||||||
.With("tag", Tag)
|
.With("tag", Tag)
|
||||||
.With("avatar_url", AvatarUrl)
|
.With("avatar_url", AvatarUrl)
|
||||||
@ -34,7 +38,9 @@ namespace PluralKit.Core
|
|||||||
.With("front_privacy", FrontPrivacy)
|
.With("front_privacy", FrontPrivacy)
|
||||||
.With("front_history_privacy", FrontHistoryPrivacy)
|
.With("front_history_privacy", FrontHistoryPrivacy)
|
||||||
.With("pings_enabled", PingsEnabled)
|
.With("pings_enabled", PingsEnabled)
|
||||||
.With("latch_timeout", LatchTimeout);
|
.With("latch_timeout", LatchTimeout)
|
||||||
|
.With("member_limit_override", MemberLimitOverride)
|
||||||
|
.With("group_limit_override", GroupLimitOverride);
|
||||||
|
|
||||||
public new void CheckIsValid()
|
public new void CheckIsValid()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user