diff --git a/Module/ModCommands/Commands/RoleManipulation.cs b/Module/ModCommands/Commands/RoleManipulation.cs new file mode 100644 index 0000000..e6a0769 --- /dev/null +++ b/Module/ModCommands/Commands/RoleManipulation.cs @@ -0,0 +1,133 @@ +using Discord.WebSocket; +using Newtonsoft.Json.Linq; +using Noikoio.RegexBot.ConfigItem; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace Noikoio.RegexBot.Module.ModCommands.Commands +{ + // Role adding and removing is largely the same, and thus are handled in a single class. + class RoleManipulation : Command + { + protected enum CommandMode { Add, Del } + private readonly CommandMode _mode; + + private readonly EntityName _role; + private readonly string _successMsg; + // Configuration: + // "role" - string; The given role that applies to this command. + // "successmsg" - string; Messages to display on command success. Overrides default. + + protected RoleManipulation(CommandListener l, string label, JObject conf, CommandMode mode) : base(l, label, conf) + { + _mode = mode; + var rolestr = conf["role"]?.Value(); + if (string.IsNullOrWhiteSpace(rolestr)) throw new RuleImportException("Role must be provided."); + _role = new EntityName(rolestr, EntityType.Role); + _successMsg = conf["successmsg"]?.Value(); + + DefaultUsageMsg = $"{this.Trigger} [user or user ID]\n" + + (_mode == CommandMode.Add ? "Adds" : "Removes") + " the specified role " + + (_mode == CommandMode.Add ? "to" : "from") + " the given user."; + } + + #region Strings + const string FailPrefix = ":x: **Failed to apply role change:** "; + const string TargetNotFound = ":x: **Unable to determine the target user.**"; + const string RoleNotFound = ":x: **Failed to determine the specified role for this command.**"; + const string Success = ":white_check_mark: Successfully {0} role for **{1}**."; + #endregion + + public override async Task Invoke(SocketGuild g, SocketMessage msg) + { + string[] line = msg.Content.Split(new char[] { ' ' }, 3, StringSplitOptions.RemoveEmptyEntries); + string targetstr; + if (line.Length < 2) + { + await SendUsageMessageAsync(msg.Channel, null); + return; + } + targetstr = line[1]; + + // Retrieve target user + var (targetId, targetData) = await GetUserDataFromString(g.Id, targetstr); + if (targetId == 1) + { + await msg.Channel.SendMessageAsync(FailPrefix + FailDefault); + return; + } + if (targetId == 0) + { + await SendUsageMessageAsync(msg.Channel, TargetNotFound); + return; + } + + string targetdisp; + if (targetData != null) + targetdisp = $"{targetData.Username}#{targetData.Discriminator}"; + else + targetdisp = $"ID {targetId}"; + + // Determine role + SocketRole cmdRole; + if (_role.Id.HasValue) + { + cmdRole = g.GetRole(_role.Id.Value); + } + else + { + var res = g.Roles.Where(rn => + string.Equals(rn.Name, _role.Name, StringComparison.InvariantCultureIgnoreCase)) + .FirstOrDefault(); + if (res == null) + { + await msg.Channel.SendMessageAsync(RoleNotFound); + await Log(RoleNotFound); + return; + } + cmdRole = res; + } + + // Do the action + try + { + var u = g.GetUser(targetId); + if (_mode == CommandMode.Add) + await u.AddRoleAsync(cmdRole); + else + await u.RemoveRoleAsync(cmdRole); + await msg.Channel.SendMessageAsync(BuildSuccessMessage(targetdisp)); + } + catch (Discord.Net.HttpException ex) + { + if (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) + { + await msg.Channel.SendMessageAsync(FailPrefix + Fail403); + } + else + { + await msg.Channel.SendMessageAsync(FailPrefix + FailDefault); + await Log(ex.ToString()); + } + } + } + + private string BuildSuccessMessage(string targetstr) + { + const string defaultmsg = ":white_check_mark: Successfully {0} role for **$target**."; + string msg = _successMsg ?? string.Format(defaultmsg, _mode == CommandMode.Add ? "set" : "unset"); + return msg.Replace("$target", targetstr); + } + } + + class RoleAdd : RoleManipulation + { + public RoleAdd(CommandListener l, string label, JObject conf) : base(l, label, conf, CommandMode.Add) { } + } + + class RoleDel : RoleManipulation + { + public RoleDel(CommandListener l, string label, JObject conf) : base(l, label, conf, CommandMode.Del) { } + } +} diff --git a/Module/ModCommands/Commands/_CommandBase.cs b/Module/ModCommands/Commands/_CommandBase.cs index 0509124..703b9b0 100644 --- a/Module/ModCommands/Commands/_CommandBase.cs +++ b/Module/ModCommands/Commands/_CommandBase.cs @@ -53,7 +53,13 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands { "confreload", typeof(ConfReload) }, { "kick", typeof(Kick) }, { "say", typeof(Say) }, - { "unban", typeof(Unban) } + { "unban", typeof(Unban) }, + { "addrole", typeof(RoleAdd) }, + { "roleadd", typeof(RoleAdd) }, + { "grantrole", typeof(RoleAdd) }, + { "delrole", typeof(RoleDel) }, + { "roledel", typeof(RoleDel) }, + { "revokerole", typeof(RoleDel) } }); public static Command CreateInstance(CommandListener root, JProperty def)