public async Task Last(CommandContext ctx, [Description("Optional number of items to show. Default is 10")] int number = 10) { var isMod = ctx.User.IsWhitelisted(ctx.Client, ctx.Guild); 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("Username", maxWidth: 24), new AsciiColumn("User ID", disabled: !ctx.Channel.IsPrivate, alignToRight: true), new AsciiColumn("Issued by", maxWidth: 15), new AsciiColumn("On date (UTC)"), new AsciiColumn("Reason"), new AsciiColumn("Context", disabled: !ctx.Channel.IsPrivate) ); using (var db = new BotDb()) { IOrderedQueryable <Warning> query; if (showRetractions) { query = from warn in db.Warning orderby warn.Id descending select warn; } else { query = from warn in db.Warning where !warn.Retracted orderby warn.Id descending select warn; } foreach (var row in query.Take(number)) { var username = await ctx.GetUserNameAsync(row.DiscordId).ConfigureAwait(false); var modname = await ctx.GetUserNameAsync(row.IssuerId, defaultName : "Unknown mod").ConfigureAwait(false); var timestamp = row.Timestamp.HasValue ? new DateTime(row.Timestamp.Value, DateTimeKind.Utc).ToString("u") : null; if (row.Retracted) { var modnameRetracted = row.RetractedBy.HasValue ? await ctx.GetUserNameAsync(row.RetractedBy.Value, defaultName : "Unknown mod").ConfigureAwait(false) : ""; var timestampRetracted = row.RetractionTimestamp.HasValue ? new DateTime(row.RetractionTimestamp.Value, DateTimeKind.Utc).ToString("u") : null; table.Add(row.Id.ToString(), "-", username, row.DiscordId.ToString(), modnameRetracted, timestampRetracted, row.RetractionReason, ""); table.Add(row.Id.ToString(), "+", username.StrikeThrough(), row.DiscordId.ToString().StrikeThrough(), modname.StrikeThrough(), timestamp.StrikeThrough(), row.Reason.StrikeThrough(), row.FullReason.StrikeThrough()); } 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); }
public async Task By(CommandContext ctx, ulong moderatorId, [Description("Optional number of items to show. Default is 10")] int number = 10) { if (number < 1) { number = 10; } var table = new AsciiTable( new AsciiColumn("ID", alignToRight: true), new AsciiColumn("Username", maxWidth: 24), new AsciiColumn("User ID", disabled: !ctx.Channel.IsPrivate, alignToRight: true), new AsciiColumn("On date (UTC)"), new AsciiColumn("Reason"), new AsciiColumn("Context", disabled: !ctx.Channel.IsPrivate) ); await using var db = new BotDb(); var query = from warn in db.Warning where warn.IssuerId == moderatorId && !warn.Retracted orderby warn.Id descending select warn; foreach (var row in query.Take(number)) { var username = await ctx.GetUserNameAsync(row.DiscordId).ConfigureAwait(false); 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); }
public async Task Users(CommandContext ctx, [Description("Optional number of items to show. Default is 10")] int number = 10) { try { if (number < 1) { number = 10; } var table = new AsciiTable( new AsciiColumn("Username", maxWidth: 24), new AsciiColumn("User ID", disabled: !ctx.Channel.IsPrivate, alignToRight: true), new AsciiColumn("Count", alignToRight: true), new AsciiColumn("All time", alignToRight: true) ); await using var db = new BotDb(); var query = from warn in db.Warning.AsEnumerable() group warn by warn.DiscordId into userGroup let row = new { discordId = userGroup.Key, count = userGroup.Count(w => !w.Retracted), total = userGroup.Count() } orderby row.count descending select row; foreach (var row in query.Take(number)) { 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:"******"SQL query for this command is broken at the moment", true).ConfigureAwait(false); } }
public async Task Users(CommandContext ctx, [Description("Optional number of items to show. Default is 10")] int number = 10) { var isMod = ctx.User.IsWhitelisted(ctx.Client, ctx.Guild); if (number < 1) { number = 10; } var table = new AsciiTable( new AsciiColumn("Username", maxWidth: 24), new AsciiColumn("User ID", disabled: !ctx.Channel.IsPrivate, alignToRight: true), new AsciiColumn("Count", alignToRight: true), new AsciiColumn("All time", alignToRight: true) ); using (var db = new BotDb()) { var query = from warn in db.Warning group warn by warn.DiscordId into userGroup let row = new { discordId = userGroup.Key, count = userGroup.Count(w => !w.Retracted), total = userGroup.Count() } orderby row.count descending select row; foreach (var row in query.Take(number)) { 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); }
public async Task List(CommandContext ctx) { var table = new AsciiTable( new AsciiColumn("Username", maxWidth: 32), new AsciiColumn("Sudo") ); foreach (var mod in ModProvider.Mods.Values.OrderByDescending(m => m.Sudoer)) { table.Add(await ctx.GetUserNameAsync(mod.DiscordId), mod.Sudoer ? "✅" :""); } await ctx.SendAutosplitMessageAsync(table.ToString()).ConfigureAwait(false); }
public async Task List(CommandContext ctx) { using var db = new BotDb(); var selectExpr = db.ForcedNicknames.AsNoTracking(); if (ctx.Guild != null) { selectExpr = selectExpr.Where(mem => mem.GuildId == ctx.Guild.Id); } var forcedNicknames = ( from m in selectExpr.AsEnumerable() orderby m.UserId, m.Nickname let result = new { m.UserId, m.Nickname } select result ).ToList(); if (forcedNicknames.Count == 0) { await ctx.RespondAsync("No users with forced nicknames").ConfigureAwait(false); return; } var table = new AsciiTable( new AsciiColumn("ID", !ctx.Channel.IsPrivate || !ctx.User.IsWhitelisted(ctx.Client)), new AsciiColumn("Username"), new AsciiColumn("Forced nickname") ); var previousUser = 0ul; foreach (var forcedNickname in forcedNicknames.Distinct()) { var sameUser = forcedNickname.UserId == previousUser; var username = sameUser ? "" : await ctx.GetUserNameAsync(forcedNickname.UserId).ConfigureAwait(false); table.Add(sameUser ? "" : forcedNickname.UserId.ToString(), username, forcedNickname.Nickname); previousUser = forcedNickname.UserId; } await ctx.SendAutosplitMessageAsync(table.ToString()).ConfigureAwait(false); }
public async Task List(CommandContext ctx) { const string linkPrefix = "discord.gg/"; await using var db = new BotDb(); var whitelistedInvites = await db.WhitelistedInvites.ToListAsync().ConfigureAwait(false); if (whitelistedInvites.Count == 0) { await ctx.Channel.SendMessageAsync("There are no whitelisted discord servers").ConfigureAwait(false); return; } var table = new AsciiTable( new AsciiColumn("ID", alignToRight: true), new AsciiColumn("Server ID", alignToRight: true), new AsciiColumn("Invite", disabled: !ctx.Channel.IsPrivate), new AsciiColumn("Server Name") ); foreach (var item in whitelistedInvites) { string?guildName = null; if (!string.IsNullOrEmpty(item.InviteCode)) { try { var invite = await ctx.Client.GetInviteByCodeAsync(item.InviteCode).ConfigureAwait(false); guildName = invite.Guild.Name; } catch { } } if (string.IsNullOrEmpty(guildName)) { try { var guild = await ctx.Client.GetGuildAsync(item.GuildId).ConfigureAwait(false); guildName = guild.Name; } catch { } } if (string.IsNullOrEmpty(guildName)) { guildName = item.Name ?? ""; } var link = ""; if (!string.IsNullOrEmpty(item.InviteCode)) { link = linkPrefix + item.InviteCode; } //discord expands invite links even if they're inside the code block for some reason table.Add(item.Id.ToString(), item.GuildId.ToString(), link + StringUtils.InvisibleSpacer, guildName.Sanitize()); } var result = new StringBuilder() .AppendLine("Whitelisted discord servers:") .Append(table); await ctx.SendAutosplitMessageAsync(result).ConfigureAwait(false); }
//note: be sure to pass a sanitized userName private static async Task ListUserWarningsAsync(DiscordClient client, DiscordMessage message, ulong userId, string userName, bool skipIfOne = true) { try { var isWhitelisted = client.GetMember(message.Author)?.IsWhitelisted() is true; if (message.Author.Id != userId && !isWhitelisted) { Config.Log.Error($"Somehow {message.Author.Username} ({message.Author.Id}) triggered warning list for {userId}"); return; } var channel = message.Channel; var isPrivate = channel.IsPrivate; int count, removed; bool isKot, isDoggo; await using var db = new BotDb(); count = await db.Warning.CountAsync(w => w.DiscordId == userId && !w.Retracted).ConfigureAwait(false); removed = await db.Warning.CountAsync(w => w.DiscordId == userId && w.Retracted).ConfigureAwait(false); isKot = db.Kot.Any(k => k.UserId == userId); isDoggo = db.Doggo.Any(d => d.UserId == userId); if (count == 0) { if (isKot && isDoggo) { if (new Random().NextDouble() < 0.5) { isKot = false; } else { isDoggo = false; } } var msg = (removed, isPrivate, isKot, isDoggo) switch { (0, _, true, false) => $"{userName} has no warnings, is an upstanding kot, and a paw bean of this community", (0, _, false, true) => $"{userName} has no warnings, is a good boy, and a wiggling tail of this community", (0, _, _, _) => $"{userName} has no warnings, is an upstanding citizen, and a pillar of this community", (_, true, _, _) => $"{userName} has no warnings ({removed} retracted warning{(removed == 1 ? "" : "s")})", (_, _, true, false) => $"{userName} has no warnings, but are they a good kot?", (_, _, false, true) => $"{userName} has no warnings, but are they a good boy?", _ => $"{userName} has no warnings", }; await message.Channel.SendMessageAsync(msg).ConfigureAwait(false); if (!isPrivate || removed == 0) { return; } } if (count == 1 && skipIfOne) { return; } const int maxWarningsInPublicChannel = 3; var showCount = Math.Min(maxWarningsInPublicChannel, count); var table = new AsciiTable( new AsciiColumn("ID", alignToRight: true), new AsciiColumn("±", disabled: !isPrivate || !isWhitelisted), new AsciiColumn("By", maxWidth: 15), new AsciiColumn("On date (UTC)"), new AsciiColumn("Reason"), new AsciiColumn("Context", disabled: !isPrivate, maxWidth: 4096) ); IQueryable <Warning> query = db.Warning.Where(w => w.DiscordId == userId).OrderByDescending(w => w.Id); if (!isPrivate || !isWhitelisted) { query = query.Where(w => !w.Retracted); } if (!isPrivate && !isWhitelisted) { query = query.Take(maxWarningsInPublicChannel); } foreach (var warning in await query.ToListAsync().ConfigureAwait(false)) { if (warning.Retracted) { if (isWhitelisted && isPrivate) { var retractedByName = warning.RetractedBy.HasValue ? await client.GetUserNameAsync(channel, warning.RetractedBy.Value, isPrivate, "unknown mod").ConfigureAwait(false) : ""; var retractionTimestamp = warning.RetractionTimestamp.HasValue ? new DateTime(warning.RetractionTimestamp.Value, DateTimeKind.Utc).ToString("u") : ""; table.Add(warning.Id.ToString(), "-", retractedByName, retractionTimestamp, warning.RetractionReason ?? "", ""); var issuerName = warning.IssuerId == 0 ? "" : await client.GetUserNameAsync(channel, warning.IssuerId, isPrivate, "unknown mod").ConfigureAwait(false); var timestamp = warning.Timestamp.HasValue ? new DateTime(warning.Timestamp.Value, DateTimeKind.Utc).ToString("u") : ""; table.Add(warning.Id.ToString().StrikeThrough(), "+", issuerName.StrikeThrough(), timestamp.StrikeThrough(), warning.Reason.StrikeThrough(), warning.FullReason.StrikeThrough()); } } else { var issuerName = warning.IssuerId == 0 ? "" : await client.GetUserNameAsync(channel, warning.IssuerId, isPrivate, "unknown mod").ConfigureAwait(false); var timestamp = warning.Timestamp.HasValue ? new DateTime(warning.Timestamp.Value, DateTimeKind.Utc).ToString("u") : ""; table.Add(warning.Id.ToString(), "+", issuerName, timestamp, warning.Reason, warning.FullReason); } } var result = new StringBuilder("Warning list for ").Append(userName); if (!isPrivate && !isWhitelisted && count > maxWarningsInPublicChannel) { result.Append($" (last {showCount} of {count}, full list in DMs)"); } result.AppendLine(":").Append(table); await channel.SendAutosplitMessageAsync(result).ConfigureAwait(false); }
public async Task List(CommandContext ctx) { var table = new AsciiTable( new AsciiColumn("ID", alignToRight: true), new AsciiColumn("Trigger"), new AsciiColumn("Validation"), new AsciiColumn("Context"), new AsciiColumn("Actions"), new AsciiColumn("Custom message") ); using (var db = new BotDb()) { var duplicates = new Dictionary <string, FilterContext>(StringComparer.InvariantCultureIgnoreCase); var filters = await db.Piracystring.Where(ps => !ps.Disabled).OrderBy(ps => ps.String.ToUpperInvariant()).AsNoTracking().ToListAsync().ConfigureAwait(false); var nonUniqueTriggers = ( from f in filters group f by f.String.ToUpperInvariant() into g where g.Count() > 1 select g.Key ).ToList(); foreach (var t in nonUniqueTriggers) { var duplicateFilters = filters.Where(ps => ps.String.Equals(t, StringComparison.InvariantCultureIgnoreCase)).ToList(); foreach (FilterContext fctx in Enum.GetValues(typeof(FilterContext))) { if (duplicateFilters.Count(f => (f.Context & fctx) == fctx) > 1) { if (duplicates.TryGetValue(t, out var fctxs)) { duplicates[t] = fctxs | fctx; } else { duplicates[t] = fctx; } } } } foreach (var item in filters) { var ctxl = item.Context.ToString(); if (duplicates.Count > 0 && duplicates.TryGetValue(item.String, out var fctx) && (item.Context & fctx) != 0) { ctxl = "❗ " + ctxl; } table.Add( item.Id.ToString(), item.String.Sanitize(), item.ValidatingRegex, ctxl, item.Actions.ToFlagsString(), string.IsNullOrEmpty(item.CustomMessage) ? "" : "✅" ); } } await ctx.SendAutosplitMessageAsync(table.ToString()).ConfigureAwait(false); await ctx.RespondAsync(FilterActionExtensions.GetLegend()).ConfigureAwait(false); }
//note: be sure to pass a sanitized userName private static async Task ListUserWarningsAsync(DiscordClient client, DiscordMessage message, ulong userId, string userName, bool skipIfOne = true) { try { var isWhitelisted = client.GetMember(message.Author)?.IsWhitelisted() ?? false; if (message.Author.Id != userId && !isWhitelisted) { Config.Log.Error($"Somehow {message.Author.Username} ({message.Author.Id}) triggered warning list for {userId}"); return; } var channel = message.Channel; var isPrivate = channel.IsPrivate; int count, removed; using (var db = new BotDb()) { count = await db.Warning.CountAsync(w => w.DiscordId == userId && !w.Retracted).ConfigureAwait(false); removed = await db.Warning.CountAsync(w => w.DiscordId == userId && w.Retracted).ConfigureAwait(false); } if (count == 0) { if (removed == 0) { await message.RespondAsync(userName + " has no warnings, is a standup citizen, and a pillar of this community").ConfigureAwait(false); } else { await message.RespondAsync(userName + " has no warnings" + (isPrivate ? $" ({removed} retracted warning{(removed == 1 ? "" : "s")})" : "")).ConfigureAwait(false); } return; } if (count == 1 && skipIfOne) { return; } const int maxWarningsInPublicChannel = 3; using (var db = new BotDb()) { var showCount = Math.Min(maxWarningsInPublicChannel, count); var table = new AsciiTable( new AsciiColumn("ID", alignToRight: true), new AsciiColumn("±", disabled: !isPrivate || !isWhitelisted), new AsciiColumn("By", maxWidth: 15), new AsciiColumn("On date (UTC)"), new AsciiColumn("Reason"), new AsciiColumn("Context", disabled: !isPrivate, maxWidth: 4096) ); IQueryable <Warning> query = db.Warning.Where(w => w.DiscordId == userId).OrderByDescending(w => w.Id); if (!isPrivate || !isWhitelisted) { query = query.Where(w => !w.Retracted); } if (!isPrivate && !isWhitelisted) { query = query.Take(maxWarningsInPublicChannel); } foreach (var warning in await query.ToListAsync().ConfigureAwait(false)) { if (warning.Retracted) { if (isWhitelisted && isPrivate) { var retractedByName = !warning.RetractedBy.HasValue ? "" : await client.GetUserNameAsync(channel, warning.RetractedBy.Value, isPrivate, "unknown mod").ConfigureAwait(false); var retractionTimestamp = warning.RetractionTimestamp.HasValue ? new DateTime(warning.RetractionTimestamp.Value, DateTimeKind.Utc).ToString("u") : null; table.Add(warning.Id.ToString(), "-", retractedByName, retractionTimestamp, warning.RetractionReason, ""); var issuerName = warning.IssuerId == 0 ? "" : await client.GetUserNameAsync(channel, warning.IssuerId, isPrivate, "unknown mod").ConfigureAwait(false); var timestamp = warning.Timestamp.HasValue ? new DateTime(warning.Timestamp.Value, DateTimeKind.Utc).ToString("u") : null; table.Add(warning.Id.ToString().StrikeThrough(), "+", issuerName.StrikeThrough(), timestamp.StrikeThrough(), warning.Reason.StrikeThrough(), warning.FullReason.StrikeThrough()); } } else { var issuerName = warning.IssuerId == 0 ? "" : await client.GetUserNameAsync(channel, warning.IssuerId, isPrivate, "unknown mod").ConfigureAwait(false); var timestamp = warning.Timestamp.HasValue ? new DateTime(warning.Timestamp.Value, DateTimeKind.Utc).ToString("u") : null; table.Add(warning.Id.ToString(), "+", issuerName, timestamp, warning.Reason, warning.FullReason); } } var result = new StringBuilder("Warning list for ").Append(userName); if (!isPrivate && !isWhitelisted && count > maxWarningsInPublicChannel) { result.Append($" (last {showCount} of {count}, full list in DMs)"); } result.AppendLine(":").Append(table); await channel.SendAutosplitMessageAsync(result).ConfigureAwait(false); } } catch (Exception e) { Config.Log.Warn(e); } }
public async Task List(CommandContext ctx) { var table = new AsciiTable( new AsciiColumn("ID", alignToRight: true), new AsciiColumn("Trigger"), new AsciiColumn("Validation", maxWidth: 2048), new AsciiColumn("Context", maxWidth: 4096), new AsciiColumn("Actions"), new AsciiColumn("Custom message", maxWidth: 2048) ); await using var db = new BotDb(); var duplicates = new Dictionary <string, FilterContext>(StringComparer.InvariantCultureIgnoreCase); var filters = db.Piracystring.Where(ps => !ps.Disabled).AsNoTracking().AsEnumerable().OrderBy(ps => ps.String.ToUpperInvariant()).ToList(); var nonUniqueTriggers = ( from f in filters group f by f.String.ToUpperInvariant() into g where g.Count() > 1 select g.Key ).ToList(); foreach (var t in nonUniqueTriggers) { var duplicateFilters = filters.Where(ps => ps.String.Equals(t, StringComparison.InvariantCultureIgnoreCase)).ToList(); foreach (FilterContext fctx in Enum.GetValues(typeof(FilterContext))) { if (duplicateFilters.Count(f => (f.Context & fctx) == fctx) > 1) { if (duplicates.TryGetValue(t, out var fctxDup)) { duplicates[t] = fctxDup | fctx; } else { duplicates[t] = fctx; } } } } foreach (var item in filters) { var ctxl = item.Context.ToString(); if (duplicates.Count > 0 && duplicates.TryGetValue(item.String, out var fctx) && (item.Context & fctx) != 0) { ctxl = "❗ " + ctxl; } table.Add( item.Id.ToString(), item.String.Sanitize(), item.ValidatingRegex ?? "", ctxl, item.Actions.ToFlagsString(), item.CustomMessage ?? "" ); } var result = new StringBuilder(table.ToString(false)).AppendLine() .AppendLine(FilterActionExtensions.GetLegend("")); await using var output = Config.MemoryStreamManager.GetStream(); //await using (var gzip = new GZipStream(output, CompressionLevel.Optimal, true)) await using (var writer = new StreamWriter(output, leaveOpen: true)) await writer.WriteAsync(result.ToString()).ConfigureAwait(false); output.Seek(0, SeekOrigin.Begin); await ctx.RespondAsync(new DiscordMessageBuilder().WithFile("filters.txt", output)).ConfigureAwait(false); }