1
0
Fork 1
mirror of https://github.com/TeamOctolings/Octobot.git synced 2025-01-31 09:09:00 +03:00
Octobot/Boyfriend/CommandProcessor.cs

271 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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.Text;
using System.Text.RegularExpressions;
using Boyfriend.Commands;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
namespace Boyfriend;
public class CommandProcessor {
private const string Success = ":white_check_mark: ";
private const string MissingArgument = ":keyboard: ";
private const string InvalidArgument = ":construction: ";
private const string NoAccess = ":no_entry_sign: ";
private const string CantInteract = ":vertical_traffic_light: ";
public static readonly Command[] Commands = {
new BanCommand(), new ClearCommand(), new HelpCommand(),
new KickCommand(), new MuteCommand(), new PingCommand(),
new SettingsCommand(), new UnbanCommand(), new UnmuteCommand()
};
private static readonly Dictionary<string, Regex> RegexCache = new();
private static readonly Regex MentionRegex = new(Regex.Escape("<@855023234407333888>"));
private readonly StringBuilder _stackedPrivateFeedback = new();
private readonly StringBuilder _stackedPublicFeedback = new();
private readonly StringBuilder _stackedReplyMessage = new();
private readonly List<Task> _tasks = new();
public readonly SocketCommandContext Context;
public bool ConfigWriteScheduled = false;
public CommandProcessor(SocketUserMessage message) {
Context = new SocketCommandContext(Boyfriend.Client, message);
}
public async Task HandleCommand() {
_stackedReplyMessage.Clear();
_stackedPrivateFeedback.Clear();
_stackedPublicFeedback.Clear();
var guild = Context.Guild;
var config = Boyfriend.GetGuildConfig(guild.Id);
if (GetMember().Roles.Contains(Utils.GetMuteRole(guild))) {
await Context.Message.ReplyAsync(Messages.UserCannotUnmuteThemselves);
return;
}
Regex regex;
if (RegexCache.ContainsKey(config["Prefix"])) { regex = RegexCache[config["Prefix"]]; } else {
regex = new Regex(Regex.Escape(config["Prefix"]));
RegexCache.Add(config["Prefix"], regex);
}
var list = Context.Message.Content.Split("\n");
foreach (var line in list) {
RunCommandOnLine(line, regex);
if (_stackedReplyMessage.Length > 0) _ = Context.Channel.TriggerTypingAsync();
}
await Task.WhenAll(_tasks);
if (ConfigWriteScheduled) await Boyfriend.WriteGuildConfig(guild.Id);
if (_stackedReplyMessage.Length > 0) _ = Context.Message.ReplyAsync(_stackedReplyMessage.ToString());
var adminChannel = Utils.GetAdminLogChannel(guild.Id);
var systemChannel = guild.SystemChannel;
if (_stackedPrivateFeedback.Length > 0 && adminChannel != null && adminChannel.Id != Context.Message.Channel.Id)
_ = Utils.SilentSendAsync(adminChannel, _stackedPrivateFeedback.ToString());
if (_stackedPublicFeedback.Length > 0 && systemChannel != null && systemChannel.Id != adminChannel?.Id
&& systemChannel.Id != Context.Message.Channel.Id)
_ = Utils.SilentSendAsync(systemChannel, _stackedPublicFeedback.ToString());
}
private void RunCommandOnLine(string line, Regex regex) {
foreach (var command in Commands) {
var lineNoMention = regex.Replace(MentionRegex.Replace(line, "", 1), "", 1);
if (lineNoMention == line
|| !command.Aliases.Contains(regex.Replace(lineNoMention, "", 1).Trim().ToLower().Split()[0]))
continue;
var args = line.Split().Skip(1).ToArray();
_tasks.Add(command.Run(this, args));
}
}
public void Reply(string response, string? customEmoji = null) {
Utils.SafeAppendToBuilder(_stackedReplyMessage, $"{customEmoji ?? Success}{response}", Context.Message);
}
public void Audit(string action, bool isPublic = true) {
var format = string.Format(Messages.FeedbackFormat, Context.User.Mention, action);
if (isPublic) Utils.SafeAppendToBuilder(_stackedPublicFeedback, format, Context.Guild.SystemChannel);
Utils.SafeAppendToBuilder(_stackedPrivateFeedback, format, Utils.GetAdminLogChannel(Context.Guild.Id));
}
public string? GetRemaining(string[] from, int startIndex, string? argument) {
if (startIndex >= from.Length && argument != null)
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{MissingArgument}{Utils.GetMessage($"Missing{argument}")}", Context.Message);
else
return string.Join(" ", from, startIndex, from.Length - startIndex);
return null;
}
public SocketUser? GetUser(string[] args, int index, string? argument) {
if (index >= args.Length) {
Utils.SafeAppendToBuilder(_stackedReplyMessage, $"{MissingArgument}{Messages.MissingUser}",
Context.Message);
return null;
}
var user = Utils.ParseUser(args[index]);
if (user == null && argument != null)
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Messages.InvalidUser, args[index])}", Context.Message);
return user;
}
public bool HasPermission(GuildPermission permission) {
if (!Context.Guild.CurrentUser.GuildPermissions.Has(permission)) {
Utils.SafeAppendToBuilder(_stackedReplyMessage, $"{NoAccess}{Utils.GetMessage($"BotCannot{permission}")}",
Context.Message);
return false;
}
if (Context.Guild.GetUser(Context.User.Id).GuildPermissions.Has(permission)
|| Context.Guild.Owner.Id == Context.User.Id) return true;
Utils.SafeAppendToBuilder(_stackedReplyMessage, $"{NoAccess}{Utils.GetMessage($"UserCannot{permission}")}",
Context.Message);
return false;
}
public SocketGuildUser? GetMember(SocketUser user, string? argument) {
var member = Context.Guild.GetUser(user.Id);
if (member == null && argument != null)
Utils.SafeAppendToBuilder(_stackedReplyMessage, $":x: {Messages.UserNotInGuild}", Context.Message);
return member;
}
public SocketGuildUser? GetMember(string[] args, int index, string? argument) {
if (index >= args.Length) {
Utils.SafeAppendToBuilder(_stackedReplyMessage, $"{MissingArgument}{Messages.MissingMember}",
Context.Message);
return null;
}
var member = Context.Guild.GetUser(Utils.ParseMention(args[index]));
if (member == null && argument != null)
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Messages.InvalidMember, Utils.Wrap(args[index]))}", Context.Message);
return member;
}
private SocketGuildUser GetMember() {
return Context.Guild.GetUser(Context.User.Id);
}
public ulong? GetBan(string[] args, int index) {
if (index >= args.Length) {
Utils.SafeAppendToBuilder(_stackedReplyMessage, $"{MissingArgument}{Messages.MissingUser}",
Context.Message);
return null;
}
var id = Utils.ParseMention(args[index]);
if (Context.Guild.GetBanAsync(id) != null) return id;
Utils.SafeAppendToBuilder(_stackedReplyMessage, Messages.UserNotBanned, Context.Message);
return null;
}
public int? GetNumberRange(string[] args, int index, int min, int max, string? argument) {
if (index >= args.Length) {
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{MissingArgument}{string.Format(Messages.MissingNumber, min.ToString(), max.ToString())}",
Context.Message);
return null;
}
if (!int.TryParse(args[index], out var i)) {
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Utils.GetMessage($"{argument}Invalid"), min.ToString(), max.ToString(), Utils.Wrap(args[index]))}",
Context.Message);
return null;
}
if (argument == null) return i;
if (i < min) {
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Utils.GetMessage($"{argument}TooSmall"), min.ToString())}",
Context.Message);
return null;
}
if (i <= max) return i;
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Utils.GetMessage($"{argument}TooLarge"), max.ToString())}",
Context.Message);
return null;
}
public static TimeSpan GetTimeSpan(string[] args, int index) {
var infinity = TimeSpan.FromMilliseconds(-1);
if (index >= args.Length)
return infinity;
var chars = args[index].AsSpan();
var numberBuilder = Boyfriend.StringBuilder;
int days = 0, hours = 0, minutes = 0, seconds = 0;
foreach (var c in chars)
if (char.IsDigit(c)) { numberBuilder.Append(c); } else {
if (numberBuilder.Length == 0) return infinity;
switch (c) {
case 'd' or 'D' or 'д' or 'Д':
days += int.Parse(numberBuilder.ToString());
numberBuilder.Clear();
break;
case 'h' or 'H' or 'ч' or 'Ч':
hours += int.Parse(numberBuilder.ToString());
numberBuilder.Clear();
break;
case 'm' or 'M' or 'м' or 'М':
minutes += int.Parse(numberBuilder.ToString());
numberBuilder.Clear();
break;
case 's' or 'S' or 'с' or 'С':
seconds += int.Parse(numberBuilder.ToString());
numberBuilder.Clear();
break;
default: return infinity;
}
}
numberBuilder.Clear();
return new TimeSpan(days, hours, minutes, seconds);
}
public bool CanInteractWith(SocketGuildUser user, string action) {
if (Context.Guild.Owner.Id == Context.User.Id) return true;
if (Context.Guild.Owner.Id == user.Id) {
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{CantInteract}{Utils.GetMessage($"UserCannot{action}Owner")}", Context.Message);
return false;
}
if (Context.User.Id == user.Id) {
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{CantInteract}{Utils.GetMessage($"UserCannot{action}Themselves")}", Context.Message);
return false;
}
if (Context.Guild.CurrentUser.Id == user.Id) {
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{CantInteract}{Utils.GetMessage($"UserCannot{action}Bot")}", Context.Message);
return false;
}
if (Context.Guild.CurrentUser.Hierarchy <= user.Hierarchy) {
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{CantInteract}{Utils.GetMessage($"BotCannot{action}Target")}", Context.Message);
return false;
}
if (GetMember().Hierarchy > user.Hierarchy) return true;
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{CantInteract}{Utils.GetMessage($"UserCannot{action}Target")}", Context.Message);
return false;
}
}