mirror of
https://github.com/RPCS3/discord-bot.git
synced 2026-01-31 01:25:22 +01:00
fix warns, part 2
This commit is contained in:
@@ -12,19 +12,24 @@ public class WarningAutoCompleteProvider: IAutoCompleteProvider
|
||||
if (!authorized)
|
||||
return [new($"{Config.Reactions.Denied} You are not authorized to use this command.", -1)];
|
||||
|
||||
//var user = context.Arguments.FirstOrDefault(kvp => kvp.Key.Name.Equals("user") && kvp.Value is DiscordUser).Value as DiscordUser;
|
||||
Expression<Func<Warning, bool>> filter = context.Command.Name is nameof(Warnings.Revert)
|
||||
Expression<Func<Warning, bool>> filter = context.Command.Name is "revert"
|
||||
? w => w.Retracted
|
||||
: w => !w.Retracted;
|
||||
if (context.Options.FirstOrDefault(o => o is { Name: "user", Value: ulong })?.Value is ulong userId)
|
||||
filter = context.Command.Name is "revert"
|
||||
? w => w.Retracted && w.DiscordId == userId
|
||||
: w => !w.Retracted && w.DiscordId == userId;
|
||||
|
||||
await using var db = new BotDb();
|
||||
IEnumerable<Warning> result;
|
||||
List<Warning> result;
|
||||
if (context.UserInput is not { Length: > 0 } prefix)
|
||||
result = db.Warning
|
||||
result = await db.Warning
|
||||
.OrderByDescending(w => w.Id)
|
||||
.Where(filter)
|
||||
.Take(25)
|
||||
.AsNoTracking()
|
||||
.AsEnumerable();
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
prefix = prefix.ToLowerInvariant();
|
||||
@@ -36,16 +41,27 @@ public class WarningAutoCompleteProvider: IAutoCompleteProvider
|
||||
.Where(filter)
|
||||
.Where(w => w.Id.ToString().Contains(prefix) || w.Reason.Contains(prefix))
|
||||
.Take(50);
|
||||
result = prefixMatches
|
||||
result = await prefixMatches
|
||||
.Concat(substringMatches)
|
||||
.Distinct()
|
||||
.OrderByDescending(i => i.Id)
|
||||
.Take(25)
|
||||
.AsNoTracking()
|
||||
.AsEnumerable();
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
var userIds = result
|
||||
.Select(w => w.DiscordId)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
var userNames = new Dictionary<ulong, string>(userIds.Count);
|
||||
foreach (var id in userIds)
|
||||
userNames[id] = await context.Client.GetUserNameAsync(context.Channel, id).ConfigureAwait(false);
|
||||
return result.Select(
|
||||
w => new DiscordAutoCompleteChoice($"{w.Id}: {w.Timestamp?.AsUtc():O}: {w.Reason}", w.Id)
|
||||
w => new DiscordAutoCompleteChoice(
|
||||
$"{w.Id}: {w.Timestamp?.AsUtc():yyyy-MM-dd HH:mmz}: {userNames[w.DiscordId]} - {w.Reason}",
|
||||
w.Id
|
||||
)
|
||||
).ToList();
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ internal static class BotStatus
|
||||
var sortedTerms = StatsStorage.GetExplainStats();
|
||||
var totalExplains = sortedTerms.Sum(t => t.stat);
|
||||
var top = sortedTerms.Take(5).ToList();
|
||||
if (top.Count == 0)
|
||||
if (top.Count is 0)
|
||||
return;
|
||||
|
||||
var statsBuilder = new StringBuilder();
|
||||
|
||||
@@ -209,6 +209,7 @@ internal static class ForcedNicknames
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
[Command("🔍 Dump"), SlashCommandTypes(DiscordApplicationCommandType.UserContextMenu)]
|
||||
[Description("Print hexadecimal binary representation of an UTF-8 encoded user name for diagnostic purposes")]
|
||||
public static async ValueTask Dump(UserCommandContext ctx, DiscordUser discordUser)
|
||||
@@ -226,6 +227,7 @@ internal static class ForcedNicknames
|
||||
}
|
||||
await ctx.RespondAsync(result, ephemeral: true).ConfigureAwait(false);
|
||||
}
|
||||
*/
|
||||
|
||||
[Command("📝 Rename automatically"), RequiresBotModRole, SlashCommandTypes(DiscordApplicationCommandType.UserContextMenu)]
|
||||
[Description("Set automatically generated nickname without enforcing it")]
|
||||
|
||||
@@ -54,7 +54,7 @@ internal static partial class Psn
|
||||
];
|
||||
}
|
||||
await ctx.RespondAsync(embeds[0], ephemeral: ephemeral).ConfigureAwait(false);
|
||||
foreach (var embed in embeds.Skip(1).Take(5))
|
||||
foreach (var embed in embeds.Skip(1).Take(EmbedPager.MaxFollowupMessages))
|
||||
await ctx.FollowupAsync(embed, ephemeral: ephemeral).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ internal static partial class Sudo
|
||||
table.Add(await ctx.GetUserNameAsync(mod.DiscordId), mod.Sudoer ? "✅" :"");
|
||||
var pages = AutosplitResponseHelper.AutosplitMessage(table.ToString());
|
||||
await ctx.RespondAsync(pages[0], ephemeral: ephemeral).ConfigureAwait(false);
|
||||
foreach (var page in pages.Skip(1).Take(4))
|
||||
foreach (var page in pages.Skip(1).Take(EmbedPager.MaxFollowupMessages))
|
||||
await ctx.FollowupAsync(page, ephemeral: ephemeral).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ internal static class WarningsContextMenus
|
||||
public static ValueTask WarnMessageAuthor(MessageCommandContext ctx, DiscordMessage message)
|
||||
=> Warn(ctx, message, null);
|
||||
|
||||
[Command("🔍 Show warnings"), SlashCommandTypes(DiscordApplicationCommandType.UserContextMenu)]
|
||||
public static ValueTask ShowWarnings(UserCommandContext ctx, DiscordUser user)
|
||||
=> Warnings.ListGroup.List(ctx, user);
|
||||
|
||||
private static async ValueTask Warn(SlashCommandContext ctx, DiscordMessage? message = null, DiscordUser? user = null)
|
||||
{
|
||||
var interactivity = ctx.Extension.ServiceProvider.GetService<InteractivityExtension>();
|
||||
@@ -72,7 +76,7 @@ internal static class WarningsContextMenus
|
||||
.AddMention(UserMention.All);
|
||||
await ctx.Channel.SendMessageAsync(userMsg).ConfigureAwait(false);
|
||||
}
|
||||
await Warnings.ListUserWarningsAsync(ctx.Client, ctx.Interaction, user.Id, user.Username.Sanitize()).ConfigureAwait(false);
|
||||
await Warnings.ListUserWarningsAsync(ctx.Client, interaction, user.Id, user.Username.Sanitize()).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -5,37 +5,31 @@ using DSharpPlus.Commands.Converters;
|
||||
|
||||
namespace CompatBot.Commands;
|
||||
|
||||
/*
|
||||
internal sealed partial class Warnings
|
||||
internal static partial class Warnings
|
||||
{
|
||||
[Command("list"), TextAlias("show")]
|
||||
[Command("list")]
|
||||
[Description("Allows to list warnings in various ways. Users can only see their own warnings.")]
|
||||
public class ListGroup
|
||||
internal static class ListGroup
|
||||
{
|
||||
[Command("me"), DefaultGroupCommand]
|
||||
[Description("List your own warning list")]
|
||||
public async Task List(CommandContext ctx)
|
||||
=> await List(ctx, ctx.Message.Author).ConfigureAwait(false);
|
||||
|
||||
[Command("user")]
|
||||
[Description("Show warning list for a user. Default is to show warning list for yourself")]
|
||||
public async Task List(CommandContext ctx, [Description("Discord user to list warnings for")] DiscordUser user)
|
||||
[Description("Show warning list for a user")]
|
||||
public static async ValueTask List(SlashCommandContext ctx, DiscordUser user)
|
||||
{
|
||||
await ctx.DeferResponseAsync(true).ConfigureAwait(false);
|
||||
if (await CheckListPermissionAsync(ctx, user.Id).ConfigureAwait(false))
|
||||
await ListUserWarningsAsync(ctx.Client, ctx.Message, user.Id, user.Username.Sanitize(), false);
|
||||
await ListUserWarningsAsync(ctx.Client, ctx.Interaction, user.Id, user.Username.Sanitize(), skipIfOne: false, useFollowup: true);
|
||||
}
|
||||
|
||||
[Command("user")]
|
||||
public async Task List(CommandContext ctx, [Description("Id of the user to list warnings for")] ulong userId)
|
||||
{
|
||||
if (await CheckListPermissionAsync(ctx, userId).ConfigureAwait(false))
|
||||
await ListUserWarningsAsync(ctx.Client, ctx.Message, userId, $"<@{userId}>", false);
|
||||
}
|
||||
|
||||
[Command("users"), TextAlias("top"), RequiresBotModRole, TriggersTyping]
|
||||
[Description("List users with warnings, sorted from most warned to least")]
|
||||
public async Task Users(CommandContext ctx, [Description("Optional number of items to show. Default is 10")] int number = 10)
|
||||
[Command("top")]
|
||||
[Description("List top users with warnings")]
|
||||
public static async ValueTask Users(
|
||||
SlashCommandContext ctx,
|
||||
[Description("Number of items to show. Default is 10")]
|
||||
int number = 10
|
||||
)
|
||||
{
|
||||
var ephemeral = !ctx.Channel.IsSpamChannel() && !ctx.Channel.IsOfftopicChannel();
|
||||
await ctx.DeferResponseAsync(ephemeral).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (number < 1)
|
||||
@@ -58,19 +52,28 @@ internal sealed partial class Warnings
|
||||
var username = await ctx.GetUserNameAsync(row.discordId).ConfigureAwait(false);
|
||||
table.Add(username, row.discordId.ToString(), row.count.ToString(), row.total.ToString());
|
||||
}
|
||||
await ctx.SendAutosplitMessageAsync(new StringBuilder("Warning count per user:").Append(table)).ConfigureAwait(false);
|
||||
var pages = AutosplitResponseHelper.AutosplitMessage(new StringBuilder("Warning count per user:").Append(table).ToString());
|
||||
await ctx.RespondAsync(pages[0], ephemeral: ephemeral).ConfigureAwait(false);
|
||||
foreach (var page in pages.Skip(1).Take(EmbedPager.MaxFollowupMessages))
|
||||
await ctx.FollowupAsync(page, ephemeral: ephemeral).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Config.Log.Error(e);
|
||||
await ctx.ReactWithAsync(Config.Reactions.Failure, "SQL query for this command is broken at the moment", true).ConfigureAwait(false);
|
||||
await ctx.RespondAsync($"{Config.Reactions.Failure} Failed to execute the command: {e.Message}".Trim(EmbedPager.MaxMessageLength), ephemeral: true).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("mods"), TextAlias("mtop"), RequiresBotModRole, TriggersTyping]
|
||||
[Description("List bot mods, sorted by the number of warnings issued")]
|
||||
public async Task Mods(CommandContext ctx, [Description("Optional number of items to show. Default is 10")] int number = 10)
|
||||
[Command("mods")]
|
||||
[Description("List top bot mods giving warnings")]
|
||||
public static async ValueTask Mods(
|
||||
SlashCommandContext ctx,
|
||||
[Description("Number of items to show. Default is 10")]
|
||||
int number = 10
|
||||
)
|
||||
{
|
||||
var ephemeral = !ctx.Channel.IsSpamChannel() && !ctx.Channel.IsOfftopicChannel();
|
||||
await ctx.DeferResponseAsync(ephemeral).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (number < 1)
|
||||
@@ -95,19 +98,27 @@ internal sealed partial class Warnings
|
||||
username = "Unknown";
|
||||
table.Add(username, row.userId.ToString(), row.count.ToString(), row.total.ToString());
|
||||
}
|
||||
await ctx.SendAutosplitMessageAsync(new StringBuilder("Warnings issued per bot mod:").Append(table)).ConfigureAwait(false);
|
||||
var pages = AutosplitResponseHelper.AutosplitMessage(new StringBuilder("Warnings issued per bot mod:").Append(table).ToString());
|
||||
await ctx.RespondAsync(pages[0], ephemeral: ephemeral).ConfigureAwait(false);
|
||||
foreach (var page in pages.Skip(1).Take(EmbedPager.MaxFollowupMessages))
|
||||
await ctx.FollowupAsync(page, ephemeral: ephemeral).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Config.Log.Error(e);
|
||||
await ctx.ReactWithAsync(Config.Reactions.Failure, "SQL query for this command is broken at the moment", true).ConfigureAwait(false);
|
||||
await ctx.RespondAsync($"{Config.Reactions.Failure} Failed to execute the command: {e.Message}".Trim(EmbedPager.MaxMessageLength), ephemeral: true).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("by"), RequiresBotModRole]
|
||||
[Command("by")]
|
||||
[Description("Shows warnings issued by the specified moderator")]
|
||||
public async Task By(CommandContext ctx, ulong moderatorId, [Description("Optional number of items to show. Default is 10")] int number = 10)
|
||||
public static async ValueTask By(
|
||||
SlashCommandContext ctx,
|
||||
DiscordUser moderator,
|
||||
[Description("Number of items to show. Default is 10")] int number = 10
|
||||
)
|
||||
{
|
||||
await ctx.DeferResponseAsync(true).ConfigureAwait(false);
|
||||
if (number < 1)
|
||||
number = 10;
|
||||
var table = new AsciiTable(
|
||||
@@ -120,7 +131,7 @@ internal sealed partial class Warnings
|
||||
);
|
||||
await using var db = new BotDb();
|
||||
var query = from warn in db.Warning
|
||||
where warn.IssuerId == moderatorId && !warn.Retracted
|
||||
where warn.IssuerId == moderator.Id && !warn.Retracted
|
||||
orderby warn.Id descending
|
||||
select warn;
|
||||
foreach (var row in query.Take(number))
|
||||
@@ -129,50 +140,38 @@ internal sealed partial class Warnings
|
||||
var timestamp = row.Timestamp.HasValue ? new DateTime(row.Timestamp.Value, DateTimeKind.Utc).ToString("u") : "";
|
||||
table.Add(row.Id.ToString(), username, row.DiscordId.ToString(), timestamp, row.Reason, row.FullReason);
|
||||
}
|
||||
var modName = await ctx.GetUserNameAsync(moderatorId, defaultName: "Unknown mod").ConfigureAwait(false);
|
||||
await ctx.SendAutosplitMessageAsync(new StringBuilder($"Recent warnings issued by {modName}:").Append(table)).ConfigureAwait(false);
|
||||
|
||||
var modName = moderator.Username;
|
||||
var pages = AutosplitResponseHelper.AutosplitMessage(new StringBuilder($"Recent warnings issued by {modName}:").Append(table).ToString());
|
||||
await ctx.RespondAsync(pages[0], ephemeral: true).ConfigureAwait(false);
|
||||
foreach (var page in pages.Skip(1).Take(EmbedPager.MaxFollowupMessages))
|
||||
await ctx.FollowupAsync(page, ephemeral: true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Command("by"), RequiresBotModRole]
|
||||
public async Task By(CommandContext ctx, string me, [Description("Optional number of items to show. Default is 10")] int number = 10)
|
||||
{
|
||||
if (me.ToLowerInvariant() == "me")
|
||||
{
|
||||
await By(ctx, ctx.User.Id, number).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var user = await ((IArgumentConverter<DiscordUser>)new DiscordUserConverter()).ConvertAsync(me, ctx).ConfigureAwait(false);
|
||||
if (user.HasValue)
|
||||
await By(ctx, user.Value, number).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Command("by"), RequiresBotModRole]
|
||||
public Task By(CommandContext ctx, DiscordUser moderator, [Description("Optional number of items to show. Default is 10")] int number = 10)
|
||||
=> By(ctx, moderator.Id, number);
|
||||
|
||||
[Command("recent"), TextAlias("last", "all"), RequiresBotModRole]
|
||||
[Description("Shows last issued warnings in chronological order")]
|
||||
public async Task Last(CommandContext ctx, [Description("Optional number of items to show. Default is 10")] int number = 10)
|
||||
[Command("recent")]
|
||||
[Description("Show last issued warnings")]
|
||||
public static async ValueTask Last(
|
||||
SlashCommandContext ctx,
|
||||
[Description("Number of items to show. Default is 10")]
|
||||
int number = 10
|
||||
)
|
||||
{
|
||||
await ctx.DeferResponseAsync(true).ConfigureAwait(false);
|
||||
var isMod = await ctx.User.IsWhitelistedAsync(ctx.Client, ctx.Guild).ConfigureAwait(false);
|
||||
var showRetractions = ctx.Channel.IsPrivate && isMod;
|
||||
if (number < 1)
|
||||
number = 10;
|
||||
var table = new AsciiTable(
|
||||
new AsciiColumn("ID", alignToRight: true),
|
||||
new AsciiColumn("±", disabled: !showRetractions),
|
||||
new AsciiColumn("±", disabled: !isMod),
|
||||
new AsciiColumn("Username", maxWidth: 24),
|
||||
new AsciiColumn("User ID", disabled: !ctx.Channel.IsPrivate, alignToRight: true),
|
||||
new AsciiColumn("User ID", disabled: !isMod, alignToRight: true),
|
||||
new AsciiColumn("Issued by", maxWidth: 15),
|
||||
new AsciiColumn("On date (UTC)"),
|
||||
new AsciiColumn("Reason"),
|
||||
new AsciiColumn("Context", disabled: !ctx.Channel.IsPrivate)
|
||||
new AsciiColumn("Context", disabled: !isMod)
|
||||
);
|
||||
await using var db = new BotDb();
|
||||
IOrderedQueryable<Warning> query;
|
||||
if (showRetractions)
|
||||
if (isMod)
|
||||
query = from warn in db.Warning
|
||||
orderby warn.Id descending
|
||||
select warn;
|
||||
@@ -196,17 +195,19 @@ internal sealed partial class Warnings
|
||||
else
|
||||
table.Add(row.Id.ToString(), "+", username, row.DiscordId.ToString(), modName, timestamp, row.Reason, row.FullReason);
|
||||
}
|
||||
await ctx.SendAutosplitMessageAsync(new StringBuilder("Recent warnings:").Append(table)).ConfigureAwait(false);
|
||||
var pages = AutosplitResponseHelper.AutosplitMessage(new StringBuilder("Recent warnings:").Append(table).ToString());
|
||||
await ctx.RespondAsync(pages[0], ephemeral: true).ConfigureAwait(false);
|
||||
foreach (var page in pages.Skip(1).Take(EmbedPager.MaxFollowupMessages))
|
||||
await ctx.FollowupAsync(page, ephemeral: true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<bool> CheckListPermissionAsync(CommandContext ctx, ulong userId)
|
||||
private static async ValueTask<bool> CheckListPermissionAsync(SlashCommandContext ctx, ulong userId)
|
||||
{
|
||||
if (userId == ctx.Message.Author.Id || ModProvider.IsMod(ctx.Message.Author.Id))
|
||||
if (userId == ctx.User.Id || ModProvider.IsMod(ctx.User.Id))
|
||||
return true;
|
||||
|
||||
await ctx.ReactWithAsync(Config.Reactions.Denied, "Regular users can only view their own warnings").ConfigureAwait(false);
|
||||
await ctx.RespondAsync($"{Config.Reactions.Denied} You can only view your own warnings").ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -194,12 +194,12 @@ internal static partial class Warnings
|
||||
|
||||
//note: be sure to pass a sanitized userName
|
||||
//note2: itneraction must be deferred
|
||||
internal static async ValueTask ListUserWarningsAsync(DiscordClient client, DiscordInteraction interaction, ulong userId, string userName, bool skipIfOne = true)
|
||||
internal static async ValueTask ListUserWarningsAsync(DiscordClient client, DiscordInteraction interaction, ulong userId, string userName, bool skipIfOne = true, bool useFollowup = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var isWhitelisted = await interaction.User.IsWhitelistedAsync(client, interaction.Guild).ConfigureAwait(false);
|
||||
if (interaction.User.Id != userId && !isWhitelisted)
|
||||
var isMod = await interaction.User.IsWhitelistedAsync(client, interaction.Guild).ConfigureAwait(false);
|
||||
if (interaction.User.Id != userId && !isMod)
|
||||
{
|
||||
Config.Log.Error($"Somehow {interaction.User.Username} ({interaction.User.Id}) triggered warning list for {userId}");
|
||||
return;
|
||||
@@ -249,22 +249,22 @@ internal static partial class Warnings
|
||||
var showCount = Math.Min(maxWarningsInPublicChannel, count);
|
||||
var table = new AsciiTable(
|
||||
new AsciiColumn("ID", alignToRight: true),
|
||||
new AsciiColumn("±", disabled: !ephemeral || !isWhitelisted),
|
||||
new AsciiColumn("±", disabled: !ephemeral || !isMod),
|
||||
new AsciiColumn("By", maxWidth: 15),
|
||||
new AsciiColumn("On date (UTC)"),
|
||||
new AsciiColumn("Reason"),
|
||||
new AsciiColumn("Context", disabled: !ephemeral, maxWidth: 4096)
|
||||
new AsciiColumn("Context", disabled: !ephemeral || !isMod, maxWidth: 4096)
|
||||
);
|
||||
IQueryable<Warning> query = db.Warning.Where(w => w.DiscordId == userId).OrderByDescending(w => w.Id);
|
||||
if (!ephemeral || !isWhitelisted)
|
||||
if (!ephemeral || !isMod)
|
||||
query = query.Where(w => !w.Retracted);
|
||||
if (!ephemeral && !isWhitelisted)
|
||||
if (!ephemeral && !isMod)
|
||||
query = query.Take(maxWarningsInPublicChannel);
|
||||
foreach (var warning in await query.ToListAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (warning.Retracted)
|
||||
{
|
||||
if (isWhitelisted && ephemeral)
|
||||
if (isMod && ephemeral)
|
||||
{
|
||||
var retractedByName = warning.RetractedBy.HasValue
|
||||
? await client.GetUserNameAsync(interaction.Channel, warning.RetractedBy.Value, ephemeral, "unknown mod").ConfigureAwait(false)
|
||||
@@ -274,7 +274,7 @@ internal static partial class Warnings
|
||||
: "";
|
||||
table.Add(warning.Id.ToString(), "-", retractedByName, retractionTimestamp, warning.RetractionReason ?? "", "");
|
||||
|
||||
var issuerName = warning.IssuerId == 0
|
||||
var issuerName = warning.IssuerId is 0
|
||||
? ""
|
||||
: await client.GetUserNameAsync(interaction.Channel, warning.IssuerId, ephemeral, "unknown mod").ConfigureAwait(false);
|
||||
var timestamp = warning.Timestamp.HasValue
|
||||
@@ -285,7 +285,7 @@ internal static partial class Warnings
|
||||
}
|
||||
else
|
||||
{
|
||||
var issuerName = warning.IssuerId == 0
|
||||
var issuerName = warning.IssuerId is 0
|
||||
? ""
|
||||
: await client.GetUserNameAsync(interaction.Channel, warning.IssuerId, ephemeral, "unknown mod").ConfigureAwait(false);
|
||||
var timestamp = warning.Timestamp.HasValue
|
||||
@@ -296,19 +296,21 @@ internal static partial class Warnings
|
||||
}
|
||||
|
||||
var result = new StringBuilder("Warning list for ").Append(Formatter.Sanitize(userName));
|
||||
if (!ephemeral && !isWhitelisted && count > maxWarningsInPublicChannel)
|
||||
if (!ephemeral && !isMod && count > maxWarningsInPublicChannel)
|
||||
result.Append($" (last {showCount} of {count}, full list in DMs)");
|
||||
result.AppendLine(":").Append(table);
|
||||
var pages = AutosplitResponseHelper.AutosplitMessage(result.ToString());
|
||||
await interaction.EditOriginalResponseAsync(new(response.WithContent(pages[0]))).ConfigureAwait(false);
|
||||
foreach (var page in pages.Skip(1).Take(4))
|
||||
if (useFollowup)
|
||||
{
|
||||
var followupMsg = new DiscordFollowupMessageBuilder()
|
||||
.AsEphemeral(ephemeral)
|
||||
.WithContent(page);
|
||||
await interaction.CreateFollowupMessageAsync(followupMsg).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
foreach (var page in pages.Skip(1).Take(EmbedPager.MaxFollowupMessages))
|
||||
{
|
||||
var followupMsg = new DiscordFollowupMessageBuilder()
|
||||
.AsEphemeral(ephemeral)
|
||||
.WithContent(page);
|
||||
await interaction.CreateFollowupMessageAsync(followupMsg).ConfigureAwait(false);
|
||||
}
|
||||
} }
|
||||
catch (Exception e)
|
||||
{
|
||||
Config.Log.Warn(e);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02474" />
|
||||
<PackageReference Include="DSharpPlus.Commands" Version="5.0.0-nightly-02474" />
|
||||
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02474" />
|
||||
<PackageReference Include="DSharpPlus.Natives.Zstd" Version="1.5.7.19" />
|
||||
<PackageReference Include="Google.Apis.Drive.v3" Version="1.69.0.3703" />
|
||||
<PackageReference Include="ksemenenko.ColorThief" Version="1.1.1.4" />
|
||||
<PackageReference Include="MathParser.org-mXparser" Version="6.1.0" />
|
||||
|
||||
@@ -271,7 +271,7 @@ internal static class Config
|
||||
};
|
||||
watchdogTarget.Parameters.AddRange([new MethodCallParameter("${level}"), new("${message}")]);
|
||||
#if DEBUG
|
||||
loggingConfig.AddRule(LogLevel.Error, LogLevel.Fatal, consoleTarget);
|
||||
loggingConfig.AddRule(LogLevel.Warn, LogLevel.Fatal, consoleTarget);
|
||||
loggingConfig.AddRule(LogLevel.Trace, LogLevel.Fatal, consoleTarget, "default"); // echo all messages from default logger to the console
|
||||
#else
|
||||
loggingConfig.AddRule(LogLevel.Info, LogLevel.Fatal, consoleTarget, "default");
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
//todo: rewrite this whole thing
|
||||
/*
|
||||
using System.Text.RegularExpressions;
|
||||
using CompatBot.Utils.Extensions;
|
||||
using DSharpPlus.Commands.EventArgs;
|
||||
using DSharpPlus.Commands.Exceptions;
|
||||
using DSharpPlus.Commands.Processors.TextCommands;
|
||||
|
||||
namespace CompatBot.EventHandlers;
|
||||
|
||||
internal static partial class UnknownCommandHandler
|
||||
{
|
||||
[GeneratedRegex(
|
||||
@"^\s*(am I|(are|is|do(es)|did|can(?!\s+of\s+)|should|must|have)(n't)?|shall|shan't|may|will|won't)\b",
|
||||
RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase
|
||||
)]
|
||||
private static partial Regex BinaryQuestion();
|
||||
|
||||
public static Task OnError(CommandsExtension cne, CommandErroredEventArgs e)
|
||||
{
|
||||
OnErrorInternal(cne, e);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public static async void OnErrorInternal(CommandsExtension cne, CommandErroredEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Context is not TextCommandContext ctx)
|
||||
return;
|
||||
|
||||
if (ctx.User.IsBotSafeCheck())
|
||||
return;
|
||||
|
||||
var ex = e.Exception;
|
||||
if (ex is InvalidOperationException && ex.Message.Contains("No matching subcommands were found"))
|
||||
ex = new CommandNotFoundException(ctx.Command.Name);
|
||||
|
||||
if (ex is not CommandNotFoundException cnfe)
|
||||
{
|
||||
Config.Log.Error(e.Exception);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(cnfe.CommandName))
|
||||
return;
|
||||
|
||||
if (ctx.Prefix != Config.CommandPrefix
|
||||
&& ctx.Prefix != Config.AutoRemoveCommandPrefix
|
||||
&& ctx.Message.Content is string msgTxt
|
||||
&& (msgTxt.EndsWith("?") || BinaryQuestion().IsMatch(msgTxt.AsSpan(ctx.Prefix.Length)))
|
||||
&& ctx.Extension.Commands.TryGetValue("8ball", out var cmd))
|
||||
{
|
||||
var updatedContext = ctx.CommandsNext.CreateContext(
|
||||
ctx.Message,
|
||||
ctx.Prefix,
|
||||
cmd,
|
||||
msgTxt[ctx.Prefix.Length ..].Trim()
|
||||
);
|
||||
try { await cmd.ExecuteAsync(updatedContext).ConfigureAwait(false); } catch { }
|
||||
return;
|
||||
}
|
||||
|
||||
var content = ctx.Message.Content;
|
||||
if (content is null or {Length: <3})
|
||||
return;
|
||||
|
||||
if (ctx.Prefix == Config.CommandPrefix)
|
||||
{
|
||||
var knownCmds = GetAllRegisteredCommands(ctx);
|
||||
var termParts = content.Split(' ', 4, StringSplitOptions.RemoveEmptyEntries);
|
||||
var normalizedTerm = string.Join(' ', termParts);
|
||||
var terms = new string[termParts.Length];
|
||||
terms[0] = termParts[0].ToLowerInvariant();
|
||||
for (var i = 1; i < termParts.Length; i++)
|
||||
terms[i] = terms[i - 1] + ' ' + termParts[i].ToLowerInvariant();
|
||||
var cmdMatches = (
|
||||
from t in terms
|
||||
from kc in knownCmds
|
||||
let v = (cmd: kc.alias, fqn: kc.fqn, w: t.GetFuzzyCoefficientCached(kc.alias), arg: normalizedTerm[t.Length ..])
|
||||
where v.w is >0.5 and <1 // if it was a 100% match, we wouldn't be here
|
||||
orderby v.w descending
|
||||
select v
|
||||
)
|
||||
.DistinctBy(i => i.fqn)
|
||||
.Take(4)
|
||||
.ToList();
|
||||
var btnExplain = new DiscordButtonComponent(cmdMatches.Count == 0 ? DiscordButtonStyle.Primary : DiscordButtonStyle.Secondary, "unk:cmd:explain", "Explain this", emoji: new(DiscordEmoji.FromUnicode("🔍")));
|
||||
var btnCompat = new DiscordButtonComponent(DiscordButtonStyle.Secondary, "unk:cmd:compat", "Is this game playable?", emoji: new(DiscordEmoji.FromUnicode("🔍")));
|
||||
var btnHelp = new DiscordButtonComponent(DiscordButtonStyle.Secondary, "unk:cmd:help", "Show bot commands", emoji: new(DiscordEmoji.FromUnicode("❔")));
|
||||
var btnCancel = new DiscordButtonComponent(DiscordButtonStyle.Danger, "unk:cmd:cancel", "Ignore", emoji: new(DiscordEmoji.FromUnicode("✖")));
|
||||
var cmdEmoji = new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🤖"));
|
||||
var msgBuilder = new DiscordMessageBuilder()
|
||||
.WithContent("I'm afraid the intended command didn't spell out quite right")
|
||||
.AddComponents(btnExplain, btnCompat, btnHelp, btnCancel);
|
||||
if (cmdMatches.Count > 0)
|
||||
{
|
||||
var btnSuggest = cmdMatches.Select((m, i) => new DiscordButtonComponent(i == 0 ? DiscordButtonStyle.Primary : DiscordButtonStyle.Secondary, "unk:cmd:s:" + m.cmd, Config.CommandPrefix + m.fqn + m.arg, emoji: cmdEmoji));
|
||||
foreach (var btn in btnSuggest)
|
||||
msgBuilder.AddComponents(btn);
|
||||
}
|
||||
var interactivity = cne.Client.GetInteractivity();
|
||||
var botMsg = await DiscordMessageExtensions.UpdateOrCreateMessageAsync(null, ctx.Channel, msgBuilder).ConfigureAwait(false);
|
||||
var (_, reaction) = await interactivity.WaitForMessageOrButtonAsync(botMsg, ctx.User, TimeSpan.FromMinutes(1)).ConfigureAwait(false);
|
||||
string? newCmd = null, newArg = content;
|
||||
if (reaction?.Id is string btnId)
|
||||
{
|
||||
if (btnId == btnCompat.CustomId)
|
||||
newCmd = "c";
|
||||
else if (btnId == btnExplain.CustomId)
|
||||
newCmd = "explain";
|
||||
else if (btnId == btnHelp.CustomId)
|
||||
{
|
||||
newCmd = "help";
|
||||
newArg = null;
|
||||
}
|
||||
else if (btnId.StartsWith("unk:cmd:s:"))
|
||||
{
|
||||
newCmd = btnId["unk:cmd:s:".Length ..];
|
||||
newArg = cmdMatches.First(m => m.cmd == newCmd).arg;
|
||||
}
|
||||
}
|
||||
try { await botMsg.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
if (newCmd is not null)
|
||||
{
|
||||
var botCommand = cne.FindCommand(newCmd, out _);
|
||||
var commandCtx = cne.CreateContext(ctx.Message, ctx.Prefix, botCommand, newArg);
|
||||
await cne.ExecuteCommandAsync(commandCtx).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Config.Log.Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<(string alias, string fqn)> GetAllRegisteredCommands(CommandContext ctx)
|
||||
{
|
||||
if (allKnownBotCommands != null)
|
||||
return allKnownBotCommands;
|
||||
|
||||
static void dumpCmd(List<(string alias, string fqn)> commandList, Command cmd, string qualifiedPrefix)
|
||||
{
|
||||
foreach (var alias in cmd.Aliases.Concat([cmd.Name]))
|
||||
{
|
||||
var qualifiedAlias = qualifiedPrefix + alias;
|
||||
if (cmd is CommandGroup g)
|
||||
{
|
||||
if (g.IsExecutableWithoutSubcommands)
|
||||
commandList.Add((qualifiedAlias, cmd.QualifiedName));
|
||||
dumpChildren(g, commandList, qualifiedAlias + " ");
|
||||
}
|
||||
else
|
||||
commandList.Add((qualifiedAlias, cmd.QualifiedName));
|
||||
}
|
||||
}
|
||||
|
||||
static void dumpChildren(CommandGroup group, List<(string alias, string fqn)> commandList, string qualifiedPrefix)
|
||||
{
|
||||
foreach (var cmd in group.Children)
|
||||
dumpCmd(commandList, cmd, qualifiedPrefix);
|
||||
}
|
||||
|
||||
var result = new List<(string alias, string fqn)>();
|
||||
foreach (var cmd in ctx.CommandsNext.RegisteredCommands.Values)
|
||||
dumpCmd(result, cmd, "");
|
||||
allKnownBotCommands = result;
|
||||
#if DEBUG
|
||||
Config.Log.Debug("Total command alias permutations: " + allKnownBotCommands.Count);
|
||||
#endif
|
||||
return allKnownBotCommands;
|
||||
}
|
||||
|
||||
private static List<(string alias, string fqn)>? allKnownBotCommands;
|
||||
}
|
||||
*/
|
||||
@@ -12,6 +12,7 @@ internal static class EmbedPager
|
||||
public const int MaxFooterLength = 2048;
|
||||
public const int MaxAuthorNameLength = 256;
|
||||
public const int MaxMessageLength = 2000;
|
||||
public const int MaxFollowupMessages = 5;
|
||||
|
||||
public static IEnumerable<DiscordEmbed> BreakInEmbeds(this IEnumerable<string> lines, DiscordEmbedBuilder builder, int maxLinesPerField = 10, string? titleBase = null)
|
||||
{
|
||||
|
||||
@@ -49,7 +49,7 @@ public static class DiscordClientExtensions
|
||||
public static async ValueTask<string> GetUserNameAsync(this DiscordClient client, DiscordChannel channel, ulong userId, bool? forDmPurposes = null, string defaultName = "Unknown user")
|
||||
{
|
||||
var isPrivate = forDmPurposes ?? channel.IsPrivate;
|
||||
if (userId == 0)
|
||||
if (userId is 0)
|
||||
return "";
|
||||
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user