From 1149f2800d326fd41ee4169218153d2f92e3bfb5 Mon Sep 17 00:00:00 2001 From: Noi Date: Wed, 20 Jul 2022 18:55:08 -0700 Subject: [PATCH] Reorganized project Moved modules into the assembly itself to simplify development of further features and reduce complexity in building this project. Additionally, many small adjustments were made, including: - Add documentation to most public methods that had it missing - Minor style updates - Updated readme to reflect near-completion of this rewrite - Remove any last remaining references to old project name Kerobot - Update dependencies --- .vscode/launch.json | 4 +- .vscode/tasks.json | 6 +- {RegexBot/Common => Common}/EntityList.cs | 8 +-- {RegexBot/Common => Common}/EntityName.cs | 5 +- Common/EntityType.cs | 20 ++++++ {RegexBot/Common => Common}/FilterList.cs | 36 +++++++++-- Common/Messages.cs | 10 +++ {RegexBot/Common => Common}/Utilities.cs | 17 ++++- {RegexBot/Data => Data}/BotDatabaseContext.cs | 22 +++++-- Data/CachedGuildMessage.cs | 62 +++++++++++++++++++ Data/CachedGuildUser.cs | 36 +++++++++++ Data/CachedUser.cs | 48 ++++++++++++++ Data/Migrations/.editorconfig | 3 + ...0220610210059_InitialMigration.Designer.cs | 0 .../20220610210059_InitialMigration.cs | 0 .../BotDatabaseContextModelSnapshot.cs | 0 ...uildConfig.json => DefaultGuildConfig.json | 0 .../InstanceConfig.cs => InstanceConfig.cs | 12 +--- ...LoadException.cs => ModuleLoadException.cs | 3 +- RegexBot/ModuleLoader.cs => ModuleLoader.cs | 9 ++- .../AutoResponder/AutoResponder.cs | 0 .../AutoResponder/Definition.cs | 0 .../EntryRole/EntryRole.cs | 0 .../EntryRole/GuildData.cs | 0 .../ModCommands/Commands/BanKick.cs | 5 +- .../ModCommands/Commands/CommandConfig.cs | 0 .../ModCommands/Commands/ConfReload.cs | 0 .../ModCommands/Commands/RoleManipulation.cs | 0 .../ModCommands/Commands/Say.cs | 0 .../ModCommands/Commands/Unban.cs | 6 +- .../ModCommands/ModCommands.cs | 0 .../ModCommands/ModuleConfig.cs | 0 .../ModLogs/ModLogs.cs | 0 .../ModLogs/ModLogs_Messages.cs | 0 .../ModLogs/ModuleConfig.cs | 0 .../PendingOutRole/ModuleConfig.cs | 0 .../PendingOutRole/PendingOutRole.cs | 0 {RegexBot-Modules => Modules}/RateLimit.cs | 0 .../RegexModerator/ConfDefinition.cs | 0 .../RegexModerator/RegexModerator.cs | 0 .../RegexModerator/ResponseExecutor.cs | 4 +- .../VoiceRoleSync/ModuleConfig.cs | 0 .../VoiceRoleSync/VoiceRoleSync.cs | 0 RegexBot/Program.cs => Program.cs | 10 +-- Readme.md | 32 +++++----- RegexBot-Modules/Include.cs | 2 - RegexBot-Modules/RegexBot-Modules.csproj | 19 ------ RegexBot/RegexBot.csproj => RegexBot.csproj | 20 +++--- RegexBot.sln | 28 --------- RegexBot/Common/EntityType.cs | 12 ---- RegexBot/Common/Strings.cs | 6 -- RegexBot/Data/CachedGuildMessage.cs | 30 --------- RegexBot/Data/CachedGuildUser.cs | 16 ----- RegexBot/Data/CachedUser.cs | 21 ------- RegexBot/Data/GuildLogLine.cs | 14 ----- RegexBot/Options.cs | 33 ---------- RegexBot/RegexbotModuleAttribute.cs | 9 --- .../RegexbotClient.cs => RegexbotClient.cs | 4 +- .../RegexbotModule.cs => RegexbotModule.cs | 4 +- RegexbotModuleAttribute.cs | 8 +++ .../CommonFunctions/BanKickResult.cs | 3 +- .../CommonFunctions/CommonFunctionsService.cs | 5 -- .../CommonFunctions/Hooks.cs | 24 ++++--- .../CommonFunctions/RemovalType.cs | 7 ++- .../EntityCache/EntityCacheService.cs | 4 +- .../EntityCache/Hooks.cs | 3 +- .../EntityCache/MessageCachingSubservice.cs | 1 - .../EntityCache/UserCachingSubservice.cs | 5 +- .../Services => Services}/Logging/Hooks.cs | 1 - .../Logging/LoggingService.cs | 0 .../ModuleState/Hooks.cs | 1 - .../ModuleState/ModuleStateService.cs | 7 +-- {RegexBot/Services => Services}/Service.cs | 1 - 73 files changed, 333 insertions(+), 313 deletions(-) rename {RegexBot/Common => Common}/EntityList.cs (97%) rename {RegexBot/Common => Common}/EntityName.cs (99%) create mode 100644 Common/EntityType.cs rename {RegexBot/Common => Common}/FilterList.cs (76%) create mode 100644 Common/Messages.cs rename {RegexBot/Common => Common}/Utilities.cs (83%) rename {RegexBot/Data => Data}/BotDatabaseContext.cs (71%) create mode 100644 Data/CachedGuildMessage.cs create mode 100644 Data/CachedGuildUser.cs create mode 100644 Data/CachedUser.cs create mode 100644 Data/Migrations/.editorconfig rename {RegexBot/Data => Data}/Migrations/20220610210059_InitialMigration.Designer.cs (100%) rename {RegexBot/Data => Data}/Migrations/20220610210059_InitialMigration.cs (100%) rename {RegexBot/Data => Data}/Migrations/BotDatabaseContextModelSnapshot.cs (100%) rename RegexBot/DefaultGuildConfig.json => DefaultGuildConfig.json (100%) rename RegexBot/InstanceConfig.cs => InstanceConfig.cs (87%) rename RegexBot/ModuleLoadException.cs => ModuleLoadException.cs (66%) rename RegexBot/ModuleLoader.cs => ModuleLoader.cs (88%) rename {RegexBot-Modules => Modules}/AutoResponder/AutoResponder.cs (100%) rename {RegexBot-Modules => Modules}/AutoResponder/Definition.cs (100%) rename {RegexBot-Modules => Modules}/EntryRole/EntryRole.cs (100%) rename {RegexBot-Modules => Modules}/EntryRole/GuildData.cs (100%) rename {RegexBot-Modules => Modules}/ModCommands/Commands/BanKick.cs (97%) rename {RegexBot-Modules => Modules}/ModCommands/Commands/CommandConfig.cs (100%) rename {RegexBot-Modules => Modules}/ModCommands/Commands/ConfReload.cs (100%) rename {RegexBot-Modules => Modules}/ModCommands/Commands/RoleManipulation.cs (100%) rename {RegexBot-Modules => Modules}/ModCommands/Commands/Say.cs (100%) rename {RegexBot-Modules => Modules}/ModCommands/Commands/Unban.cs (95%) rename {RegexBot-Modules => Modules}/ModCommands/ModCommands.cs (100%) rename {RegexBot-Modules => Modules}/ModCommands/ModuleConfig.cs (100%) rename {RegexBot-Modules => Modules}/ModLogs/ModLogs.cs (100%) rename {RegexBot-Modules => Modules}/ModLogs/ModLogs_Messages.cs (100%) rename {RegexBot-Modules => Modules}/ModLogs/ModuleConfig.cs (100%) rename {RegexBot-Modules => Modules}/PendingOutRole/ModuleConfig.cs (100%) rename {RegexBot-Modules => Modules}/PendingOutRole/PendingOutRole.cs (100%) rename {RegexBot-Modules => Modules}/RateLimit.cs (100%) rename {RegexBot-Modules => Modules}/RegexModerator/ConfDefinition.cs (100%) rename {RegexBot-Modules => Modules}/RegexModerator/RegexModerator.cs (100%) rename {RegexBot-Modules => Modules}/RegexModerator/ResponseExecutor.cs (98%) rename {RegexBot-Modules => Modules}/VoiceRoleSync/ModuleConfig.cs (100%) rename {RegexBot-Modules => Modules}/VoiceRoleSync/VoiceRoleSync.cs (100%) rename RegexBot/Program.cs => Program.cs (90%) delete mode 100644 RegexBot-Modules/Include.cs delete mode 100644 RegexBot-Modules/RegexBot-Modules.csproj rename RegexBot/RegexBot.csproj => RegexBot.csproj (71%) delete mode 100644 RegexBot.sln delete mode 100644 RegexBot/Common/EntityType.cs delete mode 100644 RegexBot/Common/Strings.cs delete mode 100644 RegexBot/Data/CachedGuildMessage.cs delete mode 100644 RegexBot/Data/CachedGuildUser.cs delete mode 100644 RegexBot/Data/CachedUser.cs delete mode 100644 RegexBot/Data/GuildLogLine.cs delete mode 100644 RegexBot/Options.cs delete mode 100644 RegexBot/RegexbotModuleAttribute.cs rename RegexBot/RegexbotClient.cs => RegexbotClient.cs (96%) rename RegexBot/RegexbotModule.cs => RegexbotModule.cs (98%) create mode 100644 RegexbotModuleAttribute.cs rename {RegexBot/Services => Services}/CommonFunctions/BanKickResult.cs (97%) rename {RegexBot/Services => Services}/CommonFunctions/CommonFunctionsService.cs (93%) rename {RegexBot/Services => Services}/CommonFunctions/Hooks.cs (75%) rename {RegexBot/Services => Services}/CommonFunctions/RemovalType.cs (74%) rename {RegexBot/Services => Services}/EntityCache/EntityCacheService.cs (77%) rename {RegexBot/Services => Services}/EntityCache/Hooks.cs (98%) rename {RegexBot/Services => Services}/EntityCache/MessageCachingSubservice.cs (99%) rename {RegexBot/Services => Services}/EntityCache/UserCachingSubservice.cs (97%) rename {RegexBot/Services => Services}/Logging/Hooks.cs (99%) rename {RegexBot/Services => Services}/Logging/LoggingService.cs (100%) rename {RegexBot/Services => Services}/ModuleState/Hooks.cs (99%) rename {RegexBot/Services => Services}/ModuleState/ModuleStateService.cs (97%) rename {RegexBot/Services => Services}/Service.cs (99%) diff --git a/.vscode/launch.json b/.vscode/launch.json index 226ef29..f29b948 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,9 +10,9 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/output/Debug/net6.0/RegexBot.dll", + "program": "${workspaceFolder}/bin/Debug/net6.0/RegexBot.dll", "args": [], - "cwd": "${workspaceFolder}/RegexBot", + "cwd": "${workspaceFolder}", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console": "internalConsole", "stopAtEntry": false diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d900e19..274a943 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/RegexBot.sln", + "${workspaceFolder}/RegexBot.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/RegexBot.sln", + "${workspaceFolder}/RegexBot.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -33,7 +33,7 @@ "watch", "run", "--project", - "${workspaceFolder}/RegexBot.sln" + "${workspaceFolder}/RegexBot.csproj" ], "problemMatcher": "$msCompile" } diff --git a/RegexBot/Common/EntityList.cs b/Common/EntityList.cs similarity index 97% rename from RegexBot/Common/EntityList.cs rename to Common/EntityList.cs index a09f036..02cd86d 100644 --- a/RegexBot/Common/EntityList.cs +++ b/Common/EntityList.cs @@ -1,9 +1,6 @@ -using Discord.WebSocket; -using Newtonsoft.Json.Linq; -using System.Collections; +using System.Collections; namespace RegexBot.Common; - /// /// Represents a commonly-used configuration structure: an array of strings consisting of values. /// @@ -64,6 +61,7 @@ public class EntityList : IEnumerable { /// Checks if the parameters of the given matches with /// any entity specified in this list. /// + /// The incoming message object with which to scan for a match. /// /// Specifies if EntityName instances within this list should have their internal ID value /// updated if found during the matching process. @@ -122,4 +120,4 @@ public class EntityList : IEnumerable { public IEnumerator GetEnumerator() => _innerList.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} +} \ No newline at end of file diff --git a/RegexBot/Common/EntityName.cs b/Common/EntityName.cs similarity index 99% rename from RegexBot/Common/EntityName.cs rename to Common/EntityName.cs index 3407f87..dc7a7bc 100644 --- a/RegexBot/Common/EntityName.cs +++ b/Common/EntityName.cs @@ -1,7 +1,4 @@ -using Discord.WebSocket; - -namespace RegexBot.Common; - +namespace RegexBot.Common; /// /// Helper class that holds an entity's name, ID, or both. /// Meant to be used during configuration processing in cases where the configuration expects diff --git a/Common/EntityType.cs b/Common/EntityType.cs new file mode 100644 index 0000000..43e2352 --- /dev/null +++ b/Common/EntityType.cs @@ -0,0 +1,20 @@ +namespace RegexBot.Common; +/// +/// The type of entity specified in an . +/// +public enum EntityType { + /// Default value. Is never referenced in regular usage. + Unspecified, + /// + /// Userd when the represents a role. + /// + Role, + /// + /// Used when the represents a channel. + /// + Channel, + /// + /// Used when the represents a user. + /// + User +} diff --git a/RegexBot/Common/FilterList.cs b/Common/FilterList.cs similarity index 76% rename from RegexBot/Common/FilterList.cs rename to Common/FilterList.cs index 2507117..87e3f8b 100644 --- a/RegexBot/Common/FilterList.cs +++ b/Common/FilterList.cs @@ -1,16 +1,37 @@ -using Discord.WebSocket; -using Newtonsoft.Json.Linq; - -namespace RegexBot.Common; - +namespace RegexBot.Common; /// /// Represents commonly-used configuration regarding whitelist/blacklist filtering, including exemptions. /// public class FilterList { - public enum FilterMode { None, Whitelist, Blacklist } + /// + /// The mode at which the 's filter criteria is operating. + /// + public enum FilterMode { + /// + /// A setting which does no filtering on the list. + /// + None, + /// + /// A setting which excludes only entites not in the list, excluding those exempted. + /// + Whitelist, + /// + /// A setting which allows all entities except those in the list, but allowing those exempted. + /// + Blacklist + } + /// + /// Gets the mode at which the 's filter criteria is operating. + /// public FilterMode Mode { get; } + /// + /// Gets the inner list that this instance is using for its filtering criteria. + /// public EntityList FilteredList { get; } + /// + /// Gets the list of entities that may override filtering rules for this instance. + /// public EntityList FilterExemptions { get; } /// @@ -70,6 +91,9 @@ public class FilterList { /// Determines if the parameters of the given message match up against the filtering /// rules described within this instance. /// + /// + /// The incoming message to be checked. + /// /// /// See equivalent documentation for . /// diff --git a/Common/Messages.cs b/Common/Messages.cs new file mode 100644 index 0000000..55a92a5 --- /dev/null +++ b/Common/Messages.cs @@ -0,0 +1,10 @@ +namespace RegexBot.Common; +/// +/// Commonly used strings used throughout the bot and modules. +/// +public static class Messages { + /// + /// Gets a string generally appropriate to display in the event of a 403 error. + /// + public const string ForbiddenGenericError = "Failed to perform the action due to a permissions issue."; +} \ No newline at end of file diff --git a/RegexBot/Common/Utilities.cs b/Common/Utilities.cs similarity index 83% rename from RegexBot/Common/Utilities.cs rename to Common/Utilities.cs index a1e07fb..55578eb 100644 --- a/RegexBot/Common/Utilities.cs +++ b/Common/Utilities.cs @@ -1,6 +1,4 @@ using Discord; -using Discord.WebSocket; -using Newtonsoft.Json.Linq; using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; @@ -9,9 +7,24 @@ namespace RegexBot.Common; /// Miscellaneous utility methods useful for the bot and modules. /// public static class Utilities { + /// + /// Gets a compiled regex that matches a channel tag and pulls its snowflake value. + /// public static Regex ChannelMention { get; } = new(@"<#(?\d+)>", RegexOptions.Compiled); + + /// + /// Gets a compiled regex that matches a custom emoji and pulls its name and ID. + /// public static Regex CustomEmoji { get; } = new(@"<:(?[A-Za-z0-9_]{2,}):(?\d+)>", RegexOptions.Compiled); + + /// + /// Gets a compiled regex that matches a fully formed Discord handle, extracting the name and discriminator. + /// public static Regex DiscriminatorSearch { get; } = new(@"(.+)#(\d{4}(?!\d))", RegexOptions.Compiled); + + /// + /// Gets a compiled regex that matches a user tag and pulls its snowflake value. + /// public static Regex UserMention { get; } = new(@"<@!?(?\d+)>", RegexOptions.Compiled); /// diff --git a/RegexBot/Data/BotDatabaseContext.cs b/Data/BotDatabaseContext.cs similarity index 71% rename from RegexBot/Data/BotDatabaseContext.cs rename to Data/BotDatabaseContext.cs index e6fc0a6..c3e10d7 100644 --- a/RegexBot/Data/BotDatabaseContext.cs +++ b/Data/BotDatabaseContext.cs @@ -1,7 +1,9 @@ using Microsoft.EntityFrameworkCore; namespace RegexBot.Data; - +/// +/// Represents a database connection using the settings defined in the bot's global configuration. +/// public class BotDatabaseContext : DbContext { private static string? _npgsqlConnectionString; internal static string PostgresConnectionString { @@ -17,21 +19,31 @@ public class BotDatabaseContext : DbContext { set => _npgsqlConnectionString ??= value; } - public DbSet GuildLog { get; set; } = null!; + /// + /// Retrieves the user cache. + /// public DbSet UserCache { get; set; } = null!; + + /// + /// Retrieves the guild user cache. + /// public DbSet GuildUserCache { get; set; } = null!; + + /// + /// Retrieves the guild message cache. + /// public DbSet GuildMessageCache { get; set; } = null!; - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + /// + protected sealed override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseNpgsql(PostgresConnectionString) .UseSnakeCaseNamingConvention(); + /// protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.Entity(entity => entity.Property(e => e.Timestamp).HasDefaultValueSql("now()")); modelBuilder.Entity(entity => entity.Property(e => e.Discriminator).HasMaxLength(4).IsFixedLength()); modelBuilder.Entity(entity => { - entity.Navigation(e => e.User).AutoInclude(); entity.HasKey(e => new { e.UserId, e.GuildId }); entity.Property(e => e.FirstSeenTime).HasDefaultValueSql("now()"); }); diff --git a/Data/CachedGuildMessage.cs b/Data/CachedGuildMessage.cs new file mode 100644 index 0000000..3dafdaf --- /dev/null +++ b/Data/CachedGuildMessage.cs @@ -0,0 +1,62 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace RegexBot.Data; +/// +/// Represents an item in the guild message cache. +/// +[Table("cache_guildmessages")] +public class CachedGuildMessage { + /// + /// Gets the message's snowflake ID. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public long MessageId { get; set; } + + /// + /// Gets the message author's snowflake ID. + /// + public long AuthorId { get; set; } + + /// + /// Gets the associated guild's snowflake ID. + /// + public long GuildId { get; set; } + + /// + /// Gets the corresponding channel's snowflake ID. + /// + public long ChannelId { get; set; } + + /// + /// Gets the timestamp showing when this message was originally created. + /// + /// + /// Though it's possible to draw this from , it is stored in the database + /// as a separate field for any possible necessary use via database queries. + /// + public DateTimeOffset CreatedAt { get; set; } + + /// + /// Gets the timestamp, if any, showing when this message was last edited. + /// + public DateTimeOffset? EditedAt { get; set; } + + /// + /// Gets a list of file names thata were attached to this message. + /// + public List AttachmentNames { get; set; } = null!; + + /// + /// Gets this message's content. + /// + public string Content { get; set; } = null!; + + /// + /// If included in the query, references the associated for this entry. + /// + [ForeignKey(nameof(AuthorId))] + [InverseProperty(nameof(CachedUser.GuildMessages))] + public CachedUser Author { get; set; } = null!; +} diff --git a/Data/CachedGuildUser.cs b/Data/CachedGuildUser.cs new file mode 100644 index 0000000..3a6f14a --- /dev/null +++ b/Data/CachedGuildUser.cs @@ -0,0 +1,36 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace RegexBot.Data; +/// +/// Represents an item in the guild user cache. +/// +[Table("cache_usersinguild")] +public class CachedGuildUser { + /// + public long UserId { get; set; } + + /// + /// Gets the associated guild's snowflake ID. + /// + public long GuildId { get; set; } + + /// + public DateTimeOffset GULastUpdateTime { get; set; } + + /// + /// Gets the timestamp showing when this cache entry was first added into the database. + /// + public DateTimeOffset FirstSeenTime { get; set; } + + /// + /// Gets the user's cached nickname in the guild. + /// + public string? Nickname { get; set; } + + /// + /// If included in the query, references the associated for this entry. + /// + [ForeignKey(nameof(UserId))] + [InverseProperty(nameof(CachedUser.Guilds))] + public CachedUser User { get; set; } = null!; +} diff --git a/Data/CachedUser.cs b/Data/CachedUser.cs new file mode 100644 index 0000000..dfdcfae --- /dev/null +++ b/Data/CachedUser.cs @@ -0,0 +1,48 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace RegexBot.Data; +/// +/// Represents an item in the user cache. +/// +[Table("cache_users")] +public class CachedUser { + /// + /// Gets the user's snowflake ID. + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public long UserId { get; set; } + + /// + /// Gets the timestamp showing when this cache entry was last updated. + /// + public DateTimeOffset ULastUpdateTime { get; set; } + + /// + /// Gets the user's username value, without the discriminator. + /// + public string Username { get; set; } = null!; + + /// + /// Gets the user's discriminator value. + /// + public string Discriminator { get; set; } = null!; + + /// + /// Gets the avatar URL, if any, for the associated user. + /// + public string? AvatarUrl { get; set; } + + /// + /// If included in the query, gets the list of associated entries for this entry. + /// + [InverseProperty(nameof(CachedGuildUser.User))] + public ICollection Guilds { get; set; } = null!; + + /// + /// If included in the query, gets the list of associated entries for this entry. + /// + [InverseProperty(nameof(CachedGuildMessage.Author))] + public ICollection GuildMessages { get; set; } = null!; +} diff --git a/Data/Migrations/.editorconfig b/Data/Migrations/.editorconfig new file mode 100644 index 0000000..f7653e7 --- /dev/null +++ b/Data/Migrations/.editorconfig @@ -0,0 +1,3 @@ +[*.cs] +dotnet_analyzer_diagnostic.category-CodeQuality.severity = none +dotnet_diagnostic.CS1591.severity = none \ No newline at end of file diff --git a/RegexBot/Data/Migrations/20220610210059_InitialMigration.Designer.cs b/Data/Migrations/20220610210059_InitialMigration.Designer.cs similarity index 100% rename from RegexBot/Data/Migrations/20220610210059_InitialMigration.Designer.cs rename to Data/Migrations/20220610210059_InitialMigration.Designer.cs diff --git a/RegexBot/Data/Migrations/20220610210059_InitialMigration.cs b/Data/Migrations/20220610210059_InitialMigration.cs similarity index 100% rename from RegexBot/Data/Migrations/20220610210059_InitialMigration.cs rename to Data/Migrations/20220610210059_InitialMigration.cs diff --git a/RegexBot/Data/Migrations/BotDatabaseContextModelSnapshot.cs b/Data/Migrations/BotDatabaseContextModelSnapshot.cs similarity index 100% rename from RegexBot/Data/Migrations/BotDatabaseContextModelSnapshot.cs rename to Data/Migrations/BotDatabaseContextModelSnapshot.cs diff --git a/RegexBot/DefaultGuildConfig.json b/DefaultGuildConfig.json similarity index 100% rename from RegexBot/DefaultGuildConfig.json rename to DefaultGuildConfig.json diff --git a/RegexBot/InstanceConfig.cs b/InstanceConfig.cs similarity index 87% rename from RegexBot/InstanceConfig.cs rename to InstanceConfig.cs index e5a4f70..91f37eb 100644 --- a/RegexBot/InstanceConfig.cs +++ b/InstanceConfig.cs @@ -1,5 +1,4 @@ using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using RegexBot.Data; using System.Reflection; @@ -30,14 +29,9 @@ class InstanceConfig { /// /// Sets up instance configuration object from file and command line parameters. /// - internal InstanceConfig(string[] cmdline) { - var opts = Options.ParseOptions(cmdline); - - var path = opts.ConfigFile; - if (path == null) { // default: config.json in working directory - path = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location) - + "." + Path.DirectorySeparatorChar + "config.json"; - } + internal InstanceConfig() { + var path = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location) + + "." + Path.DirectorySeparatorChar + "config.json"; JObject conf; try { diff --git a/RegexBot/ModuleLoadException.cs b/ModuleLoadException.cs similarity index 66% rename from RegexBot/ModuleLoadException.cs rename to ModuleLoadException.cs index 34a4e0d..41f6bef 100644 --- a/RegexBot/ModuleLoadException.cs +++ b/ModuleLoadException.cs @@ -1,7 +1,8 @@ namespace RegexBot; /// -/// Represents errors that occur when a module attempts to create a new guild state object. +/// Represents an error occurring when a module attempts to create a new guild state object +/// (that is, read or refresh its configuration). /// public class ModuleLoadException : Exception { /// diff --git a/RegexBot/ModuleLoader.cs b/ModuleLoader.cs similarity index 88% rename from RegexBot/ModuleLoader.cs rename to ModuleLoader.cs index 03e59ea..3069abe 100644 --- a/RegexBot/ModuleLoader.cs +++ b/ModuleLoader.cs @@ -3,7 +3,6 @@ using System.Reflection; using System.Text; namespace RegexBot; - static class ModuleLoader { /// /// Given the instance configuration, loads all appropriate types from file specified in it. @@ -36,21 +35,21 @@ static class ModuleLoader { return modules.AsReadOnly(); } - static IEnumerable LoadModulesFromAssembly(Assembly asm, RegexbotClient k) { + static IEnumerable LoadModulesFromAssembly(Assembly asm, RegexbotClient rb) { var eligibleTypes = from type in asm.GetTypes() where !type.IsAssignableFrom(typeof(RegexbotModule)) where type.GetCustomAttribute() != null select type; - k._svcLogging.DoLog(false, nameof(ModuleLoader), $"Scanning {asm.GetName().Name}"); + rb._svcLogging.DoLog(false, nameof(ModuleLoader), $"Scanning {asm.GetName().Name}"); var newreport = new StringBuilder("---> Found module(s):"); var newmods = new List(); foreach (var t in eligibleTypes) { - var mod = Activator.CreateInstance(t, k)!; + var mod = Activator.CreateInstance(t, rb)!; newreport.Append($" {t.Name}"); newmods.Add((RegexbotModule)mod); } - k._svcLogging.DoLog(false, nameof(ModuleLoader), newreport.ToString()); + rb._svcLogging.DoLog(false, nameof(ModuleLoader), newreport.ToString()); return newmods; } } diff --git a/RegexBot-Modules/AutoResponder/AutoResponder.cs b/Modules/AutoResponder/AutoResponder.cs similarity index 100% rename from RegexBot-Modules/AutoResponder/AutoResponder.cs rename to Modules/AutoResponder/AutoResponder.cs diff --git a/RegexBot-Modules/AutoResponder/Definition.cs b/Modules/AutoResponder/Definition.cs similarity index 100% rename from RegexBot-Modules/AutoResponder/Definition.cs rename to Modules/AutoResponder/Definition.cs diff --git a/RegexBot-Modules/EntryRole/EntryRole.cs b/Modules/EntryRole/EntryRole.cs similarity index 100% rename from RegexBot-Modules/EntryRole/EntryRole.cs rename to Modules/EntryRole/EntryRole.cs diff --git a/RegexBot-Modules/EntryRole/GuildData.cs b/Modules/EntryRole/GuildData.cs similarity index 100% rename from RegexBot-Modules/EntryRole/GuildData.cs rename to Modules/EntryRole/GuildData.cs diff --git a/RegexBot-Modules/ModCommands/Commands/BanKick.cs b/Modules/ModCommands/Commands/BanKick.cs similarity index 97% rename from RegexBot-Modules/ModCommands/Commands/BanKick.cs rename to Modules/ModCommands/Commands/BanKick.cs index e8a126f..a518834 100644 --- a/RegexBot-Modules/ModCommands/Commands/BanKick.cs +++ b/Modules/ModCommands/Commands/BanKick.cs @@ -1,4 +1,5 @@ -using RegexBot.Data; +using RegexBot.Common; +using RegexBot.Data; namespace RegexBot.Modules.ModCommands.Commands; // Ban and kick commands are highly similar in implementation, and thus are handled in a single class. @@ -132,7 +133,7 @@ abstract class BanKick : CommandConfig { await ContinueInvoke(g, msg, reason, targetId, targetQuery, targetUser); } catch (Discord.Net.HttpException ex) { if (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) { - await msg.Channel.SendMessageAsync(":x: " + Strings.ForbiddenGenericError); + await msg.Channel.SendMessageAsync(":x: " + Messages.ForbiddenGenericError); } else if (ex.HttpCode == System.Net.HttpStatusCode.NotFound) { await msg.Channel.SendMessageAsync(":x: Encountered a 404 error when processing the request."); } diff --git a/RegexBot-Modules/ModCommands/Commands/CommandConfig.cs b/Modules/ModCommands/Commands/CommandConfig.cs similarity index 100% rename from RegexBot-Modules/ModCommands/Commands/CommandConfig.cs rename to Modules/ModCommands/Commands/CommandConfig.cs diff --git a/RegexBot-Modules/ModCommands/Commands/ConfReload.cs b/Modules/ModCommands/Commands/ConfReload.cs similarity index 100% rename from RegexBot-Modules/ModCommands/Commands/ConfReload.cs rename to Modules/ModCommands/Commands/ConfReload.cs diff --git a/RegexBot-Modules/ModCommands/Commands/RoleManipulation.cs b/Modules/ModCommands/Commands/RoleManipulation.cs similarity index 100% rename from RegexBot-Modules/ModCommands/Commands/RoleManipulation.cs rename to Modules/ModCommands/Commands/RoleManipulation.cs diff --git a/RegexBot-Modules/ModCommands/Commands/Say.cs b/Modules/ModCommands/Commands/Say.cs similarity index 100% rename from RegexBot-Modules/ModCommands/Commands/Say.cs rename to Modules/ModCommands/Commands/Say.cs diff --git a/RegexBot-Modules/ModCommands/Commands/Unban.cs b/Modules/ModCommands/Commands/Unban.cs similarity index 95% rename from RegexBot-Modules/ModCommands/Commands/Unban.cs rename to Modules/ModCommands/Commands/Unban.cs index 5fa2568..609ff1d 100644 --- a/RegexBot-Modules/ModCommands/Commands/Unban.cs +++ b/Modules/ModCommands/Commands/Unban.cs @@ -1,4 +1,6 @@ -namespace RegexBot.Modules.ModCommands.Commands; +using RegexBot.Common; + +namespace RegexBot.Modules.ModCommands.Commands; class Unban : CommandConfig { private readonly string _usage; @@ -43,7 +45,7 @@ class Unban : CommandConfig { } catch (Discord.Net.HttpException ex) { const string FailPrefix = ":x: **Could not unban:** "; if (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) - await msg.Channel.SendMessageAsync(FailPrefix + Strings.ForbiddenGenericError); + await msg.Channel.SendMessageAsync(FailPrefix + Messages.ForbiddenGenericError); else if (ex.HttpCode == System.Net.HttpStatusCode.NotFound) await msg.Channel.SendMessageAsync(FailPrefix + "The specified user does not exist or is not in the ban list."); else throw; diff --git a/RegexBot-Modules/ModCommands/ModCommands.cs b/Modules/ModCommands/ModCommands.cs similarity index 100% rename from RegexBot-Modules/ModCommands/ModCommands.cs rename to Modules/ModCommands/ModCommands.cs diff --git a/RegexBot-Modules/ModCommands/ModuleConfig.cs b/Modules/ModCommands/ModuleConfig.cs similarity index 100% rename from RegexBot-Modules/ModCommands/ModuleConfig.cs rename to Modules/ModCommands/ModuleConfig.cs diff --git a/RegexBot-Modules/ModLogs/ModLogs.cs b/Modules/ModLogs/ModLogs.cs similarity index 100% rename from RegexBot-Modules/ModLogs/ModLogs.cs rename to Modules/ModLogs/ModLogs.cs diff --git a/RegexBot-Modules/ModLogs/ModLogs_Messages.cs b/Modules/ModLogs/ModLogs_Messages.cs similarity index 100% rename from RegexBot-Modules/ModLogs/ModLogs_Messages.cs rename to Modules/ModLogs/ModLogs_Messages.cs diff --git a/RegexBot-Modules/ModLogs/ModuleConfig.cs b/Modules/ModLogs/ModuleConfig.cs similarity index 100% rename from RegexBot-Modules/ModLogs/ModuleConfig.cs rename to Modules/ModLogs/ModuleConfig.cs diff --git a/RegexBot-Modules/PendingOutRole/ModuleConfig.cs b/Modules/PendingOutRole/ModuleConfig.cs similarity index 100% rename from RegexBot-Modules/PendingOutRole/ModuleConfig.cs rename to Modules/PendingOutRole/ModuleConfig.cs diff --git a/RegexBot-Modules/PendingOutRole/PendingOutRole.cs b/Modules/PendingOutRole/PendingOutRole.cs similarity index 100% rename from RegexBot-Modules/PendingOutRole/PendingOutRole.cs rename to Modules/PendingOutRole/PendingOutRole.cs diff --git a/RegexBot-Modules/RateLimit.cs b/Modules/RateLimit.cs similarity index 100% rename from RegexBot-Modules/RateLimit.cs rename to Modules/RateLimit.cs diff --git a/RegexBot-Modules/RegexModerator/ConfDefinition.cs b/Modules/RegexModerator/ConfDefinition.cs similarity index 100% rename from RegexBot-Modules/RegexModerator/ConfDefinition.cs rename to Modules/RegexModerator/ConfDefinition.cs diff --git a/RegexBot-Modules/RegexModerator/RegexModerator.cs b/Modules/RegexModerator/RegexModerator.cs similarity index 100% rename from RegexBot-Modules/RegexModerator/RegexModerator.cs rename to Modules/RegexModerator/RegexModerator.cs diff --git a/RegexBot-Modules/RegexModerator/ResponseExecutor.cs b/Modules/RegexModerator/ResponseExecutor.cs similarity index 98% rename from RegexBot-Modules/RegexModerator/ResponseExecutor.cs rename to Modules/RegexModerator/ResponseExecutor.cs index 60dd26e..6aa6ea2 100644 --- a/RegexBot-Modules/RegexModerator/ResponseExecutor.cs +++ b/Modules/RegexModerator/ResponseExecutor.cs @@ -67,7 +67,7 @@ class ResponseExecutor { var result = await runLine(param); _reports.Add((cmd, result)); } catch (Discord.Net.HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) { - _reports.Add((cmd, FromError(Strings.ForbiddenGenericError))); + _reports.Add((cmd, FromError(Messages.ForbiddenGenericError))); } } @@ -141,7 +141,7 @@ class ResponseExecutor { result = await _bot.KickAsync(_guild, $"Rule '{_rule.Label}'", _user.Id, parameter, _rule.NotifyUserOfRemoval); } - if (result.ErrorForbidden) return FromError(Strings.ForbiddenGenericError); + if (result.ErrorForbidden) return FromError(Messages.ForbiddenGenericError); if (result.ErrorNotFound) return FromError("The target user is no longer in the server."); if (_rule.NotifyChannelOfRemoval) await _msg.Channel.SendMessageAsync(result.GetResultString(_bot)); return FromSuccess(result.MessageSendSuccess ? null : "Unable to send notification DM."); diff --git a/RegexBot-Modules/VoiceRoleSync/ModuleConfig.cs b/Modules/VoiceRoleSync/ModuleConfig.cs similarity index 100% rename from RegexBot-Modules/VoiceRoleSync/ModuleConfig.cs rename to Modules/VoiceRoleSync/ModuleConfig.cs diff --git a/RegexBot-Modules/VoiceRoleSync/VoiceRoleSync.cs b/Modules/VoiceRoleSync/VoiceRoleSync.cs similarity index 100% rename from RegexBot-Modules/VoiceRoleSync/VoiceRoleSync.cs rename to Modules/VoiceRoleSync/VoiceRoleSync.cs diff --git a/RegexBot/Program.cs b/Program.cs similarity index 90% rename from RegexBot/Program.cs rename to Program.cs index 662fe61..dbcf907 100644 --- a/RegexBot/Program.cs +++ b/Program.cs @@ -1,5 +1,6 @@ -using Discord; -using Discord.WebSocket; +global using Discord.WebSocket; +global using Newtonsoft.Json.Linq; +using Discord; namespace RegexBot; class Program { @@ -10,13 +11,13 @@ class Program { static RegexbotClient _main = null!; - static async Task Main(string[] args) { + static async Task Main() { StartTime = DateTimeOffset.UtcNow; Console.WriteLine("Bot start time: " + StartTime.ToString("u")); InstanceConfig cfg; try { - cfg = new InstanceConfig(args); // Program may exit within here. + cfg = new InstanceConfig(); // Program may exit within here. } catch (Exception ex) { Console.WriteLine(ex.Message); Environment.ExitCode = 1; @@ -33,7 +34,6 @@ class Program { AlwaysDownloadUsers = true }); - // Kerobot class initialization - will set up services and modules _main = new RegexbotClient(cfg, client); // Set up application close handler diff --git a/Readme.md b/Readme.md index 60bfc15..1588bd1 100644 --- a/Readme.md +++ b/Readme.md @@ -1,26 +1,14 @@ # RegexBot -**This branch is still a major work in progress, and is highly incomplete. See the legacy branch for the current working version.** +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/J3J65TW2E) RegexBot is a Discord moderation bot framework of sorts, inspired by the terrible state of Discord moderation tools a few years ago combined with my tendency to overengineer things until they into pseudo-libraries of their own right. -### Features: -* Provides a sort of in-between interface to Discord.Net that allows modules to be written for it, its benefits being: - * Putting together disparate bot features under a common interface. - * Reducing duplicate code potentially leading to an inconsistent user experience. -* Versatile JSON-based configuration. -* High detail logging and record-keeping prevents gaps in moderation that might occur with large public bots. +This bot includes a number of features which assist in handling the tedious details in a busy server with the goal of minimizing +the occurrence of hidden details, arbitrary restrictions, or annoyingly unmodifiable behavior. Its configuration allows for a very high +level of flexibility, ensuring that the bot behaves in accordance to the exact needs of your server without compromise. -This repository also contains... - -# RegexBot-Modules -An optional set of features to add to RegexBot, some of them inspired by Reddit's Automoderator. - -This module provides a number of features to assist in watching over the tedious details in a busy server with no hidden details, -arbitrary restrictions, or unmodifiable behavior. Its configuration allows for a very high level of flexibility, ensuring that the bot -behaves in accordance to the exact needs of your server. - -### Features: +### Features * Create rules based on regular expression patterns * Follow up with custom responses ranging from sending a DM to disciplinary action * Create pattern-based triggers to provide information and fun to your users @@ -29,6 +17,14 @@ behaves in accordance to the exact needs of your server. * Make things interesting by setting triggers that only activate at random * Individual rules and triggers can be whitelisted or blacklisted per-user, per-channel, or per-role * Exemptions to these filters can be applied for additional flexibility +* High detail logging and record-keeping prevents gaps in moderation that might occur with large public bots. -## Documentation +### Modules +As mentioned above, this bot also serves as a framework of sorts, allowing others to write their own modules and expand +the bot's feature set ever further. Its benefits are: +* Putting together disparate bot features under a common, consistent interface. +* Reducing duplicate code potentially leading to an inconsistent user experience. +* Versatile JSON-based configuration. + +## User documentation Coming soon? diff --git a/RegexBot-Modules/Include.cs b/RegexBot-Modules/Include.cs deleted file mode 100644 index db2e62a..0000000 --- a/RegexBot-Modules/Include.cs +++ /dev/null @@ -1,2 +0,0 @@ -global using Discord.WebSocket; -global using Newtonsoft.Json.Linq; \ No newline at end of file diff --git a/RegexBot-Modules/RegexBot-Modules.csproj b/RegexBot-Modules/RegexBot-Modules.csproj deleted file mode 100644 index 50200f0..0000000 --- a/RegexBot-Modules/RegexBot-Modules.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net6.0 - RegexBot.Modules - enable - enable - NoiTheCat - A set of standard modules for use with RegexBot. - $(SolutionDir)\output - true - embedded - - - - - - - diff --git a/RegexBot/RegexBot.csproj b/RegexBot.csproj similarity index 71% rename from RegexBot/RegexBot.csproj rename to RegexBot.csproj index a4a35bc..ce34adb 100644 --- a/RegexBot/RegexBot.csproj +++ b/RegexBot.csproj @@ -6,10 +6,9 @@ NoiTheCat Advanced and flexible Discord moderation bot. 0.0.1 - enable - enable - True - $(SolutionDir)\output + enable + enable + True @@ -21,18 +20,17 @@ - - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + diff --git a/RegexBot.sln b/RegexBot.sln deleted file mode 100644 index ac74113..0000000 --- a/RegexBot.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30114.105 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegexBot", "RegexBot\RegexBot.csproj", "{F7CDACE1-C74E-451E-A9C2-ED717BF72C1C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegexBot-Modules", "RegexBot-Modules\RegexBot-Modules.csproj", "{347A1912-4F7D-419B-A159-6671791568CC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F7CDACE1-C74E-451E-A9C2-ED717BF72C1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7CDACE1-C74E-451E-A9C2-ED717BF72C1C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7CDACE1-C74E-451E-A9C2-ED717BF72C1C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7CDACE1-C74E-451E-A9C2-ED717BF72C1C}.Release|Any CPU.Build.0 = Release|Any CPU - {347A1912-4F7D-419B-A159-6671791568CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {347A1912-4F7D-419B-A159-6671791568CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {347A1912-4F7D-419B-A159-6671791568CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {347A1912-4F7D-419B-A159-6671791568CC}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/RegexBot/Common/EntityType.cs b/RegexBot/Common/EntityType.cs deleted file mode 100644 index d8a76b8..0000000 --- a/RegexBot/Common/EntityType.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace RegexBot.Common; - -/// -/// The type of entity specified in an . -/// -public enum EntityType { - /// Default value. Is never referenced in regular usage. - Unspecified, - Role, - Channel, - User -} diff --git a/RegexBot/Common/Strings.cs b/RegexBot/Common/Strings.cs deleted file mode 100644 index 453b60a..0000000 --- a/RegexBot/Common/Strings.cs +++ /dev/null @@ -1,6 +0,0 @@ -/// -/// Commonly used strings used throughout the program and modules. -/// -public static class Strings { - public const string ForbiddenGenericError = "Failed to perform the action due to a permissions issue."; -} \ No newline at end of file diff --git a/RegexBot/Data/CachedGuildMessage.cs b/RegexBot/Data/CachedGuildMessage.cs deleted file mode 100644 index 91b5831..0000000 --- a/RegexBot/Data/CachedGuildMessage.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace RegexBot.Data; -[Table("cache_messages")] -public class CachedGuildMessage { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.None)] - public long MessageId { get; set; } - - public long AuthorId { get; set; } - - public long GuildId { get; set; } - - public long ChannelId { get; set; } - - public DateTimeOffset CreatedAt { get; set; } - - public DateTimeOffset? EditedAt { get; set; } - - public List AttachmentNames { get; set; } = null!; - - public string Content { get; set; } = null!; - - [ForeignKey(nameof(AuthorId))] - [InverseProperty(nameof(CachedUser.GuildMessages))] - public CachedUser Author { get; set; } = null!; - - internal new CachedGuildMessage MemberwiseClone() => (CachedGuildMessage)base.MemberwiseClone(); -} diff --git a/RegexBot/Data/CachedGuildUser.cs b/RegexBot/Data/CachedGuildUser.cs deleted file mode 100644 index 8b372fc..0000000 --- a/RegexBot/Data/CachedGuildUser.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.DataAnnotations.Schema; - -namespace RegexBot.Data; - -[Table("cache_userguild")] -public class CachedGuildUser { - public long UserId { get; set; } - public long GuildId { get; set; } - public DateTimeOffset GULastUpdateTime { get; set; } - public DateTimeOffset FirstSeenTime { get; set; } - public string? Nickname { get; set; } - - [ForeignKey(nameof(UserId))] - [InverseProperty(nameof(CachedUser.Guilds))] - public CachedUser User { get; set; } = null!; -} diff --git a/RegexBot/Data/CachedUser.cs b/RegexBot/Data/CachedUser.cs deleted file mode 100644 index 1b350f4..0000000 --- a/RegexBot/Data/CachedUser.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace RegexBot.Data; - -[Table("cache_user")] -public class CachedUser { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.None)] - public long UserId { get; set; } - public DateTimeOffset ULastUpdateTime { get; set; } - public string Username { get; set; } = null!; - public string Discriminator { get; set; } = null!; - public string? AvatarUrl { get; set; } - - [InverseProperty(nameof(CachedGuildUser.User))] - public ICollection Guilds { get; set; } = null!; - - [InverseProperty(nameof(CachedGuildMessage.Author))] - public ICollection GuildMessages { get; set; } = null!; -} diff --git a/RegexBot/Data/GuildLogLine.cs b/RegexBot/Data/GuildLogLine.cs deleted file mode 100644 index 00a40b5..0000000 --- a/RegexBot/Data/GuildLogLine.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System.ComponentModel.DataAnnotations.Schema; - -namespace RegexBot.Data; - -[Table("guild_log")] -[Index(nameof(GuildId))] -public class GuildLogLine { - public int Id { get; set; } - public long GuildId { get; set; } - public DateTimeOffset Timestamp { get; set; } - public string Source { get; set; } = null!; - public string Message { get; set; } = null!; -} diff --git a/RegexBot/Options.cs b/RegexBot/Options.cs deleted file mode 100644 index 73c2106..0000000 --- a/RegexBot/Options.cs +++ /dev/null @@ -1,33 +0,0 @@ -using CommandLine; -using CommandLine.Text; - -namespace RegexBot; - -/// -/// Command line options -/// -class Options { - [Option('c', "config", Default = null, - HelpText = "Custom path to instance configuration. Defaults to config.json in bot directory.")] - public string ConfigFile { get; set; } = null!; - - /// - /// Command line arguments parsed here. Depending on inputs, the program can exit here. - /// - public static Options ParseOptions(string[] args) { - // Parser will not write out to console by itself - var parser = new Parser(config => config.HelpWriter = null); - Options? opts = null; - - var result = parser.ParseArguments(args); - result.WithParsed(p => opts = p); - result.WithNotParsed(p => { - // Taking some extra steps to modify the header to make it resemble our welcome message. - var ht = HelpText.AutoBuild(result); - ht.Heading += " - https://github.com/NoiTheCat/RegexBot"; - Console.WriteLine(ht.ToString()); - Environment.Exit(1); - }); - return opts!; - } -} diff --git a/RegexBot/RegexbotModuleAttribute.cs b/RegexBot/RegexbotModuleAttribute.cs deleted file mode 100644 index d38cf0c..0000000 --- a/RegexBot/RegexbotModuleAttribute.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace RegexBot; - -/// -/// Specifies to the Kerobot module loader that the target class should be treated as a module instance. -/// When the program scans an assembly which has been specified in its instance configuration to be loaded, -/// the program searches for classes implementing that also contain this attribute. -/// -[AttributeUsage(AttributeTargets.Class, Inherited = false)] -public class RegexbotModuleAttribute : Attribute { } diff --git a/RegexBot/RegexbotClient.cs b/RegexbotClient.cs similarity index 96% rename from RegexBot/RegexbotClient.cs rename to RegexbotClient.cs index b5c1a76..9128873 100644 --- a/RegexBot/RegexbotClient.cs +++ b/RegexbotClient.cs @@ -1,8 +1,6 @@ -using Discord.WebSocket; -using System.Reflection; +using System.Reflection; namespace RegexBot; - /// /// The RegexBot client instance. /// diff --git a/RegexBot/RegexbotModule.cs b/RegexbotModule.cs similarity index 98% rename from RegexBot/RegexbotModule.cs rename to RegexbotModule.cs index bf4ccb2..4ebe99d 100644 --- a/RegexBot/RegexbotModule.cs +++ b/RegexbotModule.cs @@ -1,6 +1,4 @@ -using Discord.WebSocket; -using Newtonsoft.Json.Linq; -using RegexBot.Common; +using RegexBot.Common; using System.Diagnostics; namespace RegexBot; diff --git a/RegexbotModuleAttribute.cs b/RegexbotModuleAttribute.cs new file mode 100644 index 0000000..d6c9c0d --- /dev/null +++ b/RegexbotModuleAttribute.cs @@ -0,0 +1,8 @@ +namespace RegexBot; + +/// +/// Provides a hint to the module loader that the class it is applied to should be treated as a module instance. +/// When the program scans an assembly, it is scanned for classes which implement and have this attribute. +/// +[AttributeUsage(AttributeTargets.Class, Inherited = false)] +public class RegexbotModuleAttribute : Attribute { } diff --git a/RegexBot/Services/CommonFunctions/BanKickResult.cs b/Services/CommonFunctions/BanKickResult.cs similarity index 97% rename from RegexBot/Services/CommonFunctions/BanKickResult.cs rename to Services/CommonFunctions/BanKickResult.cs index 4ecf41d..9d5bcc3 100644 --- a/RegexBot/Services/CommonFunctions/BanKickResult.cs +++ b/Services/CommonFunctions/BanKickResult.cs @@ -1,4 +1,5 @@ using Discord.Net; +using RegexBot.Common; // Instances of this class are created by CommonFunctionService and are meant to be sent to modules, // therefore we put this in the root RegexBot namespace despite being specific to this service. @@ -104,7 +105,7 @@ public class BanKickResult { if (!MessageSendSuccess) msg += "\n(User was unable to receive notification message.)"; } else { if (ErrorNotFound) msg += ": The specified user could not be found."; - else if (ErrorForbidden) msg += ": " + Strings.ForbiddenGenericError; + else if (ErrorForbidden) msg += ": " + Messages.ForbiddenGenericError; } return msg; diff --git a/RegexBot/Services/CommonFunctions/CommonFunctionsService.cs b/Services/CommonFunctions/CommonFunctionsService.cs similarity index 93% rename from RegexBot/Services/CommonFunctions/CommonFunctionsService.cs rename to Services/CommonFunctions/CommonFunctionsService.cs index 0ab4b9b..4acae85 100644 --- a/RegexBot/Services/CommonFunctions/CommonFunctionsService.cs +++ b/Services/CommonFunctions/CommonFunctionsService.cs @@ -1,15 +1,10 @@ using Discord.Net; -using Discord.WebSocket; namespace RegexBot.Services.CommonFunctions; - /// /// Implements certain common actions that modules may want to perform. Using this service to perform those /// functions may help enforce a sense of consistency across modules when performing common actions, and may /// inform services which provide any additional features the ability to respond to those actions ahead of time. -/// -/// This is currently an experimental section. If it turns out to not be necessary, this service will be removed and -/// modules may resume executing common actions on their own. /// internal class CommonFunctionsService : Service { public CommonFunctionsService(RegexbotClient bot) : base(bot) { } diff --git a/RegexBot/Services/CommonFunctions/Hooks.cs b/Services/CommonFunctions/Hooks.cs similarity index 75% rename from RegexBot/Services/CommonFunctions/Hooks.cs rename to Services/CommonFunctions/Hooks.cs index 277f241..c6b61ef 100644 --- a/RegexBot/Services/CommonFunctions/Hooks.cs +++ b/Services/CommonFunctions/Hooks.cs @@ -1,5 +1,4 @@ -using Discord.WebSocket; -using RegexBot.Services.CommonFunctions; +using RegexBot.Services.CommonFunctions; namespace RegexBot; partial class RegexbotClient { @@ -29,7 +28,12 @@ partial class RegexbotClient { /// Similar to , but making use of an /// EntityCache lookup to determine the target. /// - /// The EntityCache search string. + /// The guild in which to attempt the ban. + /// The user, module, or service which is requesting this action to be taken. + /// The user which to perform the action to (as a query to the entity cache). + /// 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. public async Task BanAsync(SocketGuild guild, string source, string targetSearch, @@ -54,10 +58,7 @@ partial class RegexbotClient { /// Reason for the action. Sent to the guild's audit log and, if /// is , the target. /// - /// - /// Specify whether to send a direct message to the target user informing them of the action - /// (that is, a ban/kick message). - /// + /// Specify whether to send a direct message to the target user informing them of the action. public Task KickAsync(SocketGuild guild, string source, ulong targetUser, @@ -69,7 +70,14 @@ partial class RegexbotClient { /// Similar to , but making use of an /// EntityCache lookup to determine the target. /// - /// The EntityCache search string. + /// The guild in which to attempt the kick. + /// The user, module, or service which is requesting this action to be taken. + /// The user which to perform the action towards (processed as a query to the entity cache). + /// + /// Reason for the action. Sent to the guild's audit log and, if + /// is , the target. + /// + /// Specify whether to send a direct message to the target user informing them of the action. public async Task KickAsync(SocketGuild guild, string source, string targetSearch, diff --git a/RegexBot/Services/CommonFunctions/RemovalType.cs b/Services/CommonFunctions/RemovalType.cs similarity index 74% rename from RegexBot/Services/CommonFunctions/RemovalType.cs rename to Services/CommonFunctions/RemovalType.cs index 2a2ee86..750054c 100644 --- a/RegexBot/Services/CommonFunctions/RemovalType.cs +++ b/Services/CommonFunctions/RemovalType.cs @@ -1,9 +1,10 @@ -// Despite specific to CommonFunctionsService, this enum is meant to be visible by modules too, -// thus it is placed within the root namespace. -namespace RegexBot; +namespace RegexBot; /// /// Specifies possible outcomes for the removal of a user from a guild. /// +// Despite specific to CommonFunctionsService, this enum is meant to be visible by modules too, +// thus it is placed within the root namespace. +// TODO Tends to be unused except internally. Look into removing. public enum RemovalType { /// /// Default value. Not used in any actual circumstances. diff --git a/RegexBot/Services/EntityCache/EntityCacheService.cs b/Services/EntityCache/EntityCacheService.cs similarity index 77% rename from RegexBot/Services/EntityCache/EntityCacheService.cs rename to Services/EntityCache/EntityCacheService.cs index 6a3f646..ddafc27 100644 --- a/RegexBot/Services/EntityCache/EntityCacheService.cs +++ b/Services/EntityCache/EntityCacheService.cs @@ -2,9 +2,7 @@ namespace RegexBot.Services.EntityCache; /// -/// Provides and maintains a database-backed cache of entities. Portions of information collected by this -/// service may be used by modules, while other portions are useful only for external applications which may -/// require this information, such as an external web interface. +/// Provides and maintains a database-backed cache of entities. /// class EntityCacheService : Service { private readonly UserCachingSubservice _uc; diff --git a/RegexBot/Services/EntityCache/Hooks.cs b/Services/EntityCache/Hooks.cs similarity index 98% rename from RegexBot/Services/EntityCache/Hooks.cs rename to Services/EntityCache/Hooks.cs index 834009c..019756a 100644 --- a/RegexBot/Services/EntityCache/Hooks.cs +++ b/Services/EntityCache/Hooks.cs @@ -1,5 +1,4 @@ -using Discord.WebSocket; -using RegexBot.Data; +using RegexBot.Data; using RegexBot.Services.EntityCache; namespace RegexBot; diff --git a/RegexBot/Services/EntityCache/MessageCachingSubservice.cs b/Services/EntityCache/MessageCachingSubservice.cs similarity index 99% rename from RegexBot/Services/EntityCache/MessageCachingSubservice.cs rename to Services/EntityCache/MessageCachingSubservice.cs index dbea345..32c4ede 100644 --- a/RegexBot/Services/EntityCache/MessageCachingSubservice.cs +++ b/Services/EntityCache/MessageCachingSubservice.cs @@ -1,5 +1,4 @@ using Discord; -using Discord.WebSocket; using RegexBot.Data; using static RegexBot.RegexbotClient; diff --git a/RegexBot/Services/EntityCache/UserCachingSubservice.cs b/Services/EntityCache/UserCachingSubservice.cs similarity index 97% rename from RegexBot/Services/EntityCache/UserCachingSubservice.cs rename to Services/EntityCache/UserCachingSubservice.cs index ee5fc48..e69b189 100644 --- a/RegexBot/Services/EntityCache/UserCachingSubservice.cs +++ b/Services/EntityCache/UserCachingSubservice.cs @@ -1,4 +1,4 @@ -using Discord.WebSocket; +using Microsoft.EntityFrameworkCore; using RegexBot.Common; using RegexBot.Data; @@ -101,8 +101,7 @@ class UserCachingSubservice { internal CachedGuildUser? DoGuildUserQuery(ulong guildId, string search) { static CachedGuildUser? innerQuery(ulong guildId, ulong? sID, (string name, string? disc)? nameSearch) { var db = new BotDatabaseContext(); - - var query = db.GuildUserCache.Where(c => c.GuildId == (long)guildId); + var query = db.GuildUserCache.Include(gu => gu.User).Where(c => c.GuildId == (long)guildId); if (sID.HasValue) query = query.Where(c => c.UserId == (long)sID.Value); if (nameSearch != null) { diff --git a/RegexBot/Services/Logging/Hooks.cs b/Services/Logging/Hooks.cs similarity index 99% rename from RegexBot/Services/Logging/Hooks.cs rename to Services/Logging/Hooks.cs index c6e7aae..8f2aa1a 100644 --- a/RegexBot/Services/Logging/Hooks.cs +++ b/Services/Logging/Hooks.cs @@ -1,7 +1,6 @@ using RegexBot.Services.Logging; namespace RegexBot; - partial class RegexbotClient { // Access set to internal for ModuleBase and Service base class internal readonly LoggingService _svcLogging; diff --git a/RegexBot/Services/Logging/LoggingService.cs b/Services/Logging/LoggingService.cs similarity index 100% rename from RegexBot/Services/Logging/LoggingService.cs rename to Services/Logging/LoggingService.cs diff --git a/RegexBot/Services/ModuleState/Hooks.cs b/Services/ModuleState/Hooks.cs similarity index 99% rename from RegexBot/Services/ModuleState/Hooks.cs rename to Services/ModuleState/Hooks.cs index e9b5bbf..1907c26 100644 --- a/RegexBot/Services/ModuleState/Hooks.cs +++ b/Services/ModuleState/Hooks.cs @@ -1,7 +1,6 @@ using RegexBot.Services.ModuleState; namespace RegexBot; - partial class RegexbotClient { // Access set to internal for ModuleBase internal readonly ModuleStateService _svcGuildState; diff --git a/RegexBot/Services/ModuleState/ModuleStateService.cs b/Services/ModuleState/ModuleStateService.cs similarity index 97% rename from RegexBot/Services/ModuleState/ModuleStateService.cs rename to Services/ModuleState/ModuleStateService.cs index d6aa513..ccaa13b 100644 --- a/RegexBot/Services/ModuleState/ModuleStateService.cs +++ b/Services/ModuleState/ModuleStateService.cs @@ -1,11 +1,8 @@ -using Discord.WebSocket; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json; using RegexBot.Common; using System.Reflection; namespace RegexBot.Services.ModuleState; - /// /// Implements per-module storage and retrieval of guild-specific state data, most typically but not limited to configuration data. /// To that end, this service handles loading and validation of per-guild configuration files. @@ -15,8 +12,6 @@ class ModuleStateService : Service { private readonly Dictionary _moderators; private readonly Dictionary> _stateData; - const string GuildLogSource = "Configuration loader"; - public ModuleStateService(RegexbotClient bot) : base(bot) { _moderators = new(); _stateData = new(); diff --git a/RegexBot/Services/Service.cs b/Services/Service.cs similarity index 99% rename from RegexBot/Services/Service.cs rename to Services/Service.cs index bdec16b..f5ee3b2 100644 --- a/RegexBot/Services/Service.cs +++ b/Services/Service.cs @@ -1,5 +1,4 @@ namespace RegexBot.Services; - /// /// Base class for services. ///