Updates and changes to project files

- Set up vscode tasks
- Update Readme and License
- Minor style and documentation changes
This commit is contained in:
Noi 2022-06-17 23:23:25 -07:00
parent 2160b0fa4e
commit 13324999cc
9 changed files with 130 additions and 54 deletions

26
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"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",
"args": [],
"cwd": "${workspaceFolder}/RegexBot",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

41
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/RegexBot.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/RegexBot.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/RegexBot.sln"
],
"problemMatcher": "$msCompile"
}
]
}

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2018 Noikoio <noikoio1 AT gmail.com> Copyright (c) 2018-2022 Noi <noithecat AT protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -1,22 +0,0 @@
# RegexBot
**This branch contains code that is still a major work in progress, and is unusable in its current state. See the master branch for the current working version.**
RegexBot is a self-hosted Discord moderation bot that takes some inspiration from Reddit's Automoderator. It 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.
### Feature overview for 3.0:
* Modular structure allows for extra features to be written, further enhancing the bot's customizability wherever it may be deployed.
* Versatile JSON-based configuration, support for separate servers.
* High detail logging and record-keeping prevents gaps in moderation that might occur with large public bots.
### Feature overview for RegexBotModule 3.0:
* 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
* Adjustable rate limits per-trigger to prevent spam
* Specify multiple different responses to display at random when triggered
* 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
## Documentation
Coming soon.

34
Readme.md Normal file
View file

@ -0,0 +1,34 @@
# RegexBot
**This branch is still a major work in progress, and is highly incomplete. See the legacy branch for the current working version.**
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 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:
* 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
* Adjustable rate limits per-trigger to prevent spam
* Specify multiple different responses to display at random when triggered
* 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
## Documentation
Coming soon?

View file

@ -1,34 +1,28 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 16
VisualStudioVersion = 17.0.32112.339 VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RegexBot", "RegexBot\RegexBot.csproj", "{6FA3A92F-F1FC-4BA8-8018-1A05CB4C7FA3}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegexBot", "RegexBot\RegexBot.csproj", "{F7CDACE1-C74E-451E-A9C2-ED717BF72C1C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegexBot-Modules", "RegexBot-Modules\RegexBot-Modules.csproj", "{03111D82-30ED-4FDF-A512-87BDC05C6DA1}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegexBot-Modules", "RegexBot-Modules\RegexBot-Modules.csproj", "{347A1912-4F7D-419B-A159-6671791568CC}"
ProjectSection(ProjectDependencies) = postProject
{6FA3A92F-F1FC-4BA8-8018-1A05CB4C7FA3} = {6FA3A92F-F1FC-4BA8-8018-1A05CB4C7FA3}
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6FA3A92F-F1FC-4BA8-8018-1A05CB4C7FA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FA3A92F-F1FC-4BA8-8018-1A05CB4C7FA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FA3A92F-F1FC-4BA8-8018-1A05CB4C7FA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FA3A92F-F1FC-4BA8-8018-1A05CB4C7FA3}.Release|Any CPU.Build.0 = Release|Any CPU
{03111D82-30ED-4FDF-A512-87BDC05C6DA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03111D82-30ED-4FDF-A512-87BDC05C6DA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03111D82-30ED-4FDF-A512-87BDC05C6DA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03111D82-30ED-4FDF-A512-87BDC05C6DA1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
SolutionGuid = {C823EC9C-CF20-4437-8B99-72158A6DD113} {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 EndGlobalSection
EndGlobal EndGlobal

View file

@ -115,8 +115,10 @@ public class EntityList : IEnumerable<EntityName> {
/// </summary> /// </summary>
public bool IsEmpty() => _innerList.Count == 0; public bool IsEmpty() => _innerList.Count == 0;
/// <inheritdoc/>
public override string ToString() => $"Entity list contains {_innerList.Count} item(s)."; public override string ToString() => $"Entity list contains {_innerList.Count} item(s).";
/// <inheritdoc/>
public IEnumerator<EntityName> GetEnumerator() => _innerList.GetEnumerator(); public IEnumerator<EntityName> GetEnumerator() => _innerList.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

View file

@ -50,7 +50,7 @@ public class EntityName {
input = input[1..]; // Remove prefix input = input[1..]; // Remove prefix
// Input contains ID/Label separator? // Input contains ID/Label separator?
int separator = input.IndexOf("::"); var separator = input.IndexOf("::");
if (separator != -1) { if (separator != -1) {
Name = input[(separator + 2)..]; Name = input[(separator + 2)..];
if (ulong.TryParse(input.AsSpan(0, separator), out var parseOut)) { if (ulong.TryParse(input.AsSpan(0, separator), out var parseOut)) {
@ -93,7 +93,7 @@ public class EntityName {
/// Returns a string representation of this item in proper EntityName format. /// Returns a string representation of this item in proper EntityName format.
/// </summary> /// </summary>
public override string ToString() { public override string ToString() {
char pf = Prefix(Type); var pf = Prefix(Type);
if (Id.HasValue && Name != null) if (Id.HasValue && Name != null)
return $"{pf}{Id.Value}::{Name}"; return $"{pf}{Id.Value}::{Name}";
@ -109,14 +109,14 @@ public class EntityName {
/// </summary> /// </summary>
/// <param name="guild">The guild in which to search for the role.</param> /// <param name="guild">The guild in which to search for the role.</param>
/// <param name="updateMissingID"> /// <param name="updateMissingID">
/// Specifies if this EntityName instance should keep the snowflake ID of the /// Specifies if this EntityName instance should cache the snowflake ID of the
/// corresponding role found in this guild, if it is not already known by this instance. /// corresponding role found in this guild if it is not already known by this instance.
/// </param> /// </param>
public SocketRole? FindRoleIn(SocketGuild guild, bool updateMissingID = false) { public SocketRole? FindRoleIn(SocketGuild guild, bool updateMissingID = false) {
if (Type != EntityType.Role) if (Type != EntityType.Role)
throw new ArgumentException("This EntityName instance must correspond to a Role."); throw new ArgumentException("This EntityName instance must correspond to a Role.");
bool dirty = false; // flag for updating ID if possible regardless of updateMissingId setting var dirty = false; // flag for updating ID if possible regardless of updateMissingId setting
if (Id.HasValue) { if (Id.HasValue) {
var role = guild.GetRole(Id.Value); var role = guild.GetRole(Id.Value);
if (role != null) return role; if (role != null) return role;
@ -134,14 +134,14 @@ public class EntityName {
/// </summary> /// </summary>
/// <param name="guild">The guild in which to search for the user.</param> /// <param name="guild">The guild in which to search for the user.</param>
/// <param name="updateMissingID"> /// <param name="updateMissingID">
/// Specifies if this EntityName instance should keep the snowflake ID of the /// Specifies if this EntityName instance should cache the snowflake ID of the
/// corresponding user found in this guild, if it is not already known by this instance. /// corresponding user found in this guild if it is not already known by this instance.
/// </param> /// </param>
public SocketGuildUser? FindUserIn(SocketGuild guild, bool updateMissingID = false) { public SocketGuildUser? FindUserIn(SocketGuild guild, bool updateMissingID = false) {
if (Type != EntityType.User) if (Type != EntityType.User)
throw new ArgumentException("This EntityName instance must correspond to a User."); throw new ArgumentException("This EntityName instance must correspond to a User.");
bool dirty = false; // flag for updating ID if possible regardless of updateMissingId setting var dirty = false; // flag for updating ID if possible regardless of updateMissingId setting
if (Id.HasValue) { if (Id.HasValue) {
var user = guild.GetUser(Id.Value); var user = guild.GetUser(Id.Value);
if (user != null) return user; if (user != null) return user;
@ -159,14 +159,14 @@ public class EntityName {
/// </summary> /// </summary>
/// <param name="guild">The guild in which to search for the channel.</param> /// <param name="guild">The guild in which to search for the channel.</param>
/// <param name="updateMissingID"> /// <param name="updateMissingID">
/// Specifies if this EntityName instance should keep the snowflake ID of the /// Specifies if this EntityName instance should cache the snowflake ID of the
/// corresponding channel found in this guild, if it is not already known by this instance. /// corresponding channel found in this guild if it is not already known by this instance.
/// </param> /// </param>
public SocketTextChannel? FindChannelIn(SocketGuild guild, bool updateMissingID = false) { public SocketTextChannel? FindChannelIn(SocketGuild guild, bool updateMissingID = false) {
if (Type != EntityType.Channel) if (Type != EntityType.Channel)
throw new ArgumentException("This EntityName instance must correspond to a Channel."); throw new ArgumentException("This EntityName instance must correspond to a Channel.");
bool dirty = false; // flag for updating ID if possible regardless of updateMissingId setting var dirty = false; // flag for updating ID if possible regardless of updateMissingId setting
if (Id.HasValue) { if (Id.HasValue) {
var channel = guild.GetTextChannel(Id.Value); var channel = guild.GetTextChannel(Id.Value);
if (channel != null) return channel; if (channel != null) return channel;

View file

@ -71,7 +71,8 @@ public abstract class RegexbotModule {
/// <summary> /// <summary>
/// Emits a log message to the bot console that is associated with the specified guild. /// Emits a log message to the bot console that is associated with the specified guild.
/// </summary> /// </summary>
/// /// <param name="message">The log message to send. Multi-line messages are acceptable.</param> /// <param name="guild">The guld for which this log message is associated with.</param>
/// <param name="message">The log message to send. Multi-line messages are acceptable.</param>
protected void Log(SocketGuild guild, string? message) { protected void Log(SocketGuild guild, string? message) {
var gname = guild.Name ?? $"Guild ID {guild.Id}"; var gname = guild.Name ?? $"Guild ID {guild.Id}";
Bot._svcLogging.DoLog(false, $"{Name}] [{gname}", message); Bot._svcLogging.DoLog(false, $"{Name}] [{gname}", message);