using Discord.WebSocket; using Kerobot.Common; using Newtonsoft.Json.Linq; using System; using System.Diagnostics; using System.Threading.Tasks; using static Kerobot.Kerobot; namespace Kerobot { /// /// Base class for a Kerobot module. A module implements a user-facing feature and is expected to directly handle /// user input (both by means of configuration and incoming Discord events) and process it accordingly. /// /// /// Implementing classes should not rely on local variables to store runtime data regarding guilds. /// Use and . /// public abstract class ModuleBase { /// /// Retrieves the Kerobot instance. /// public Kerobot Kerobot { get; } /// /// Retrieves the Discord client instance. /// public DiscordSocketClient DiscordClient { get => Kerobot.DiscordClient; } /// /// When a module is loaded, this constructor is called. /// Services are available at this point. Do not attempt to communicate to Discord within the constructor. /// public ModuleBase(Kerobot kb) => Kerobot = kb; /// /// Gets the module name. /// This value is derived from the class's name. It is used in configuration and logging. /// public string Name => GetType().Name; /// /// Called when a guild becomes available. The implementing class should construct an object to hold /// data specific to the corresponding guild for use during runtime. /// /// Corresponding guild ID for the state data being used. Can be useful when reloading. /// JSON token holding module configuration specific to this guild. /// /// An object containing state and/or configuration information for the guild currently being processed. /// public abstract Task CreateGuildStateAsync(ulong guildID, JToken config); /// /// Retrieves the state object that corresponds with the given guild. /// /// The state object's type. /// The guild ID for which to retrieve the state object. /// The state object cast in the given type, or Default(T) if none exists. /// /// Thrown if the stored state object cannot be cast as specified. /// [DebuggerStepThrough] protected T GetGuildState(ulong guildId) => Kerobot.GetGuildState(guildId, GetType()); /// /// Appends a message to the global instance log. Use sparingly. /// /// /// Specifies if the log message should be sent to the reporting channel. /// Only messages of very high importance should use this option. /// protected Task LogAsync(string message, bool report = false) => Kerobot.InstanceLogAsync(report, Name, message); /// /// Appends a message to the log for the specified guild. /// protected Task LogAsync(ulong guild, string message) => Kerobot.GuildLogAsync(guild, Name, message); /// /// Attempts to ban the given user from the specified guild. It is greatly preferred to call this method /// instead of manually executing the equivalent method found in Discord.Net. It notifies other services /// that the action originated from the bot, and allows them to handle the action appropriately. /// /// A structure containing results of the ban operation. /// The guild in which to attempt the action. /// The user, module, or service which is requesting this action to be taken. /// The user which to perform the action to. /// Number of days of prior post history to delete on ban. Must be between 0-7. /// Reason for the action. Sent to the Audit Log and user (if specified). /// Specify whether to send a direct message to the target user informing them of the action being taken. protected Task BanAsync(SocketGuild guild, string source, ulong targetUser, int purgeDays, string reason, bool sendDMToTarget) => Kerobot.BanOrKickAsync(RemovalType.Ban, guild, source, targetUser, purgeDays, reason, sendDMToTarget); /// /// Similar to , but making use of an /// EntityCache lookup to determine the target. /// /// The EntityCache search string. protected async Task BanAsync(SocketGuild guild, string source, string targetSearch, int purgeDays, string reason, bool sendDMToTarget) { var result = await Kerobot.EcQueryUser(guild.Id, targetSearch); if (result == null) return new BanKickResult(null, false, true); return await BanAsync(guild, source, result.UserID, purgeDays, reason, sendDMToTarget); } /// /// Attempts to ban the given user from the specified guild. It is greatly preferred to call this method /// instead of manually executing the equivalent method found in Discord.Net. It notifies other services /// that the action originated from the bot, and allows them to handle the action appropriately. /// /// A structure containing results of the ban operation. /// The guild in which to attempt the action. /// The user, if any, which requested the action to be taken. /// The user which to perform the action to. /// Reason for the action. Sent to the Audit Log and user (if specified). /// Specify whether to send a direct message to the target user informing them of the action being taken. protected Task KickAsync(SocketGuild guild, string source, ulong targetUser, string reason, bool sendDMToTarget) => Kerobot.BanOrKickAsync(RemovalType.Ban, guild, source, targetUser, 0, reason, sendDMToTarget); /// /// Similar to , but making use of an /// EntityCache lookup to determine the target. /// /// The EntityCache search string. protected async Task KickAsync(SocketGuild guild, string source, string targetSearch, string reason, bool sendDMToTarget) { var result = await Kerobot.EcQueryUser(guild.Id, targetSearch); if (result == null) return new BanKickResult(null, false, true); return await KickAsync(guild, source, result.UserID, reason, sendDMToTarget); } /// /// Returns the list of moderators defined in the current guild configuration. /// /// /// An with corresponding moderator configuration data. /// In case none exists, an empty list will be returned. /// protected EntityList GetModerators(ulong guild) => Kerobot.GetModerators(guild); } /// /// Represents errors that occur when a module attempts to create a new guild state object. /// public class ModuleLoadException : Exception { /// /// Initializes this exception class with the specified error message. /// /// public ModuleLoadException(string message) : base(message) { } } }