discord-bot/CompatBot/EventHandlers/Starbucks.cs
13xforever 7879ec893a
fix member fetching
previously only client cache was searched, but now we will fetch the data from server if it's not there
this makes a bunch of stuff async tho
2023-04-21 21:08:10 +05:00

235 lines
10 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CompatBot.Commands;
using CompatBot.Utils;
using CompatBot.Utils.Extensions;
using DSharpPlus;
using DSharpPlus.Entities;
using DSharpPlus.EventArgs;
namespace CompatBot.EventHandlers;
internal static class Starbucks
{
private static readonly Dictionary<DiscordEmoji, string> TextMap = new()
{
[DiscordEmoji.FromUnicode("Ⓜ")] = "M",
[DiscordEmoji.FromUnicode("🅰")] = "A",
[DiscordEmoji.FromUnicode("🅱")] = "B",
[DiscordEmoji.FromUnicode("🆎")] = "AB",
[DiscordEmoji.FromUnicode("🅾")] = "O",
[DiscordEmoji.FromUnicode("🇦")] = "A",
[DiscordEmoji.FromUnicode("🇧")] = "B",
[DiscordEmoji.FromUnicode("🇨")] = "C",
[DiscordEmoji.FromUnicode("🇩")] = "D",
[DiscordEmoji.FromUnicode("🇪")] = "E",
[DiscordEmoji.FromUnicode("🇫")] = "F",
[DiscordEmoji.FromUnicode("🇬")] = "G",
[DiscordEmoji.FromUnicode("🇭")] = "H",
[DiscordEmoji.FromUnicode("🇮")] = "I",
[DiscordEmoji.FromUnicode("🇯")] = "G",
[DiscordEmoji.FromUnicode("🇰")] = "K",
[DiscordEmoji.FromUnicode("🇱")] = "L",
[DiscordEmoji.FromUnicode("🇲")] = "M",
[DiscordEmoji.FromUnicode("🇳")] = "N",
[DiscordEmoji.FromUnicode("🇴")] = "O",
[DiscordEmoji.FromUnicode("🇵")] = "P",
[DiscordEmoji.FromUnicode("🇶")] = "Q",
[DiscordEmoji.FromUnicode("🇷")] = "R",
[DiscordEmoji.FromUnicode("🇸")] = "S",
[DiscordEmoji.FromUnicode("🇹")] = "T",
[DiscordEmoji.FromUnicode("🇺")] = "U",
[DiscordEmoji.FromUnicode("🇻")] = "V",
[DiscordEmoji.FromUnicode("🇼")] = "W",
[DiscordEmoji.FromUnicode("🇽")] = "X",
[DiscordEmoji.FromUnicode("🇾")] = "Y",
[DiscordEmoji.FromUnicode("🇿")] = "Z",
[DiscordEmoji.FromUnicode("0\u20E3")] = "0",
[DiscordEmoji.FromUnicode("1\u20E3")] = "1",
[DiscordEmoji.FromUnicode("2\u20E3")] = "2",
[DiscordEmoji.FromUnicode("3\u20E3")] = "3",
[DiscordEmoji.FromUnicode("4\u20E3")] = "4",
[DiscordEmoji.FromUnicode("5\u20E3")] = "5",
[DiscordEmoji.FromUnicode("6\u20E3")] = "6",
[DiscordEmoji.FromUnicode("7\u20E3")] = "7",
[DiscordEmoji.FromUnicode("8\u20E3")] = "8",
[DiscordEmoji.FromUnicode("9\u20E3")] = "9",
[DiscordEmoji.FromUnicode("🔟")] = "10",
[DiscordEmoji.FromUnicode("💯")] = "100",
[DiscordEmoji.FromUnicode("🆑")] = "CL",
[DiscordEmoji.FromUnicode("🆒")] = "COOL",
[DiscordEmoji.FromUnicode("🆓")] = "FREE",
[DiscordEmoji.FromUnicode("🆔")] = "ID",
[DiscordEmoji.FromUnicode("🆕")] = "NEW",
[DiscordEmoji.FromUnicode("🆖")] = "NG",
[DiscordEmoji.FromUnicode("🆗")] = "OK",
[DiscordEmoji.FromUnicode("🆘")] = "SOS",
[DiscordEmoji.FromUnicode("🆙")] = "UP",
[DiscordEmoji.FromUnicode("🆚")] = "VS",
[DiscordEmoji.FromUnicode("⭕")] = "O",
[DiscordEmoji.FromUnicode("🔄")] = "O",
[DiscordEmoji.FromUnicode("✝")] = "T",
[DiscordEmoji.FromUnicode("❌")] = "X",
[DiscordEmoji.FromUnicode("✖")] = "X",
[DiscordEmoji.FromUnicode("❎")] = "X",
[DiscordEmoji.FromUnicode("🅿")] = "P",
[DiscordEmoji.FromUnicode("🚾")] = "WC",
[DiscordEmoji.FromUnicode("")] = "i",
[DiscordEmoji.FromUnicode("〰")] = "W",
};
public static Task Handler(DiscordClient c, MessageReactionAddEventArgs args)
=> CheckMessageAsync(c, args.Channel, args.User, args.Message, args.Emoji, false);
public static async Task CheckBacklogAsync(DiscordClient client, DiscordGuild guild)
{
try
{
var after = DateTime.UtcNow - Config.ModerationBacklogThresholdInHours;
var checkTasks = new List<Task>();
foreach (var channel in guild.Channels.Values.Where(ch => Config.Moderation.MediaChannels.Contains(ch.Id)))
{
var messages = await channel.GetMessagesCachedAsync().ConfigureAwait(false);
var messagesToCheck = from msg in messages
where msg.CreationTimestamp > after && msg.Reactions.Any(r => r.Emoji == Config.Reactions.Starbucks && r.Count >= Config.Moderation.StarbucksThreshold)
select msg;
foreach (var message in messagesToCheck)
{
var reactionUsers = await message.GetReactionsAsync(Config.Reactions.Starbucks).ConfigureAwait(false);
if (reactionUsers.Count > 0)
checkTasks.Add(CheckMessageAsync(client, channel, reactionUsers[0], message, Config.Reactions.Starbucks, true));
}
}
await Task.WhenAll(checkTasks).ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Error(e);
}
}
private static async Task CheckMessageAsync(DiscordClient client, DiscordChannel? channel, DiscordUser user, DiscordMessage message, DiscordEmoji emoji, bool isBacklog)
{
try
{
if (user.IsBotSafeCheck() || channel is null || channel.IsPrivate)
return;
// in case it's not in cache and doesn't contain any info, including Author
message = await channel.GetMessageAsync(message.Id).ConfigureAwait(false);
if (emoji == Config.Reactions.Starbucks)
await CheckMediaTalkAsync(client, channel, message, emoji).ConfigureAwait(false);
if (emoji == Config.Reactions.ShutUp && !isBacklog)
await ShutupAsync(client, user, message).ConfigureAwait(false);
if (emoji == Config.Reactions.BadUpdate && !isBacklog)
await BadUpdateAsync(client, user, message, emoji).ConfigureAwait(false);
await CheckGameFansAsync(client, channel, message).ConfigureAwait(false);
}
catch (Exception e)
{
Config.Log.Error(e);
}
}
private static async Task CheckMediaTalkAsync(DiscordClient client, DiscordChannel channel, DiscordMessage message, DiscordEmoji emoji)
{
if (!Config.Moderation.MediaChannels.Contains(channel.Id))
return;
// message.Timestamp throws if it's not in the cache AND is in local time zone
if (DateTime.UtcNow - message.CreationTimestamp > Config.ModerationBacklogThresholdInHours)
return;
if (message.Reactions.Any(r => r.Emoji == emoji && (r.IsMe || r.Count < Config.Moderation.StarbucksThreshold)))
return;
if (await message.Author.IsWhitelistedAsync(client, channel.Guild).ConfigureAwait(false))
return;
var users = await message.GetReactionsAsync(emoji).ConfigureAwait(false);
if (users.Any(u => u.IsCurrent))
return;
var members = users
.Distinct()
.Select(u => channel.Guild
.GetMemberAsync(u.Id)
.ContinueWith(ct => ct.IsCompletedSuccessfully ? ct : Task.FromResult((DiscordMember?)null), TaskScheduler.Default))
.ToList() //force eager task creation
.Select(t => t.Unwrap().ConfigureAwait(false).GetAwaiter().GetResult())
.Where(m => m != null)
.ToList();
var reporters = members.Where(m => m!.Roles.Any()).ToList();
if (reporters.Count < Config.Moderation.StarbucksThreshold)
return;
await message.ReactWithAsync(emoji).ConfigureAwait(false);
await client.ReportAsync(Config.Reactions.Starbucks + " Media talk report", message, reporters, null, ReportSeverity.Medium).ConfigureAwait(false);
}
private static async Task ShutupAsync(DiscordClient client, DiscordUser user, DiscordMessage message)
{
if (!message.Author.IsCurrent)
return;
if (message.CreationTimestamp.Add(Config.ShutupTimeLimitInMin) < DateTime.UtcNow)
return;
if (!await user.IsWhitelistedAsync(client, message.Channel.Guild).ConfigureAwait(false))
return;
await message.DeleteAsync().ConfigureAwait(false);
}
private static async Task BadUpdateAsync(DiscordClient client, DiscordUser user, DiscordMessage message, DiscordEmoji emoji)
{
if (message.Channel.Id != Config.BotChannelId)
return;
if (!await user.IsSmartlistedAsync(client, message.Channel.Guild).ConfigureAwait(false))
return;
await Moderation.ToggleBadUpdateAnnouncementAsync(message).ConfigureAwait(false);
try
{
await message.DeleteReactionAsync(emoji, user).ConfigureAwait(false);
}
catch { }
}
private static async Task CheckGameFansAsync(DiscordClient client, DiscordChannel channel, DiscordMessage message)
{
var bot = await client.GetMemberAsync(channel.Guild, client.CurrentUser).ConfigureAwait(false);
var ch = channel.IsPrivate ? channel.Users.FirstOrDefault(u => u.Id != client.CurrentUser.Id)?.Username + "'s DM" : "#" + channel.Name;
if (!channel.PermissionsFor(bot).HasPermission(Permissions.AddReactions))
{
Config.Log.Debug($"No permissions to react in {ch}");
return;
}
var mood = client.GetEmoji(":sqvat:", "😒");
if (message.Reactions.Any(r => r.Emoji == mood && r.IsMe))
return;
var reactionMsg = string.Concat(message.Reactions.Select(r => TextMap.TryGetValue(r.Emoji, out var txt) ? txt : " ")).Trim();
if (string.IsNullOrEmpty(reactionMsg))
return;
Config.Log.Debug($"Emoji text: {reactionMsg} (in {ch})");
if (reactionMsg.Contains("UFC"))
{
await message.CreateReactionAsync(mood).ConfigureAwait(false);
await message.CreateReactionAsync(DiscordEmoji.FromUnicode("🇳")).ConfigureAwait(false);
await message.CreateReactionAsync(DiscordEmoji.FromUnicode("🇴")).ConfigureAwait(false);
}
}
}