diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..e92b65c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,25 @@ +name: Docker Publish + +on: + push: + branches: + - master + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup .NET 7 + uses: actions/setup-dotnet@v3.0.3 + with: + dotnet-version: '7.0.402' + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build local Docker image + run: dotnet publish --arch x64 --os linux . + - name: Push to Docker Hub + run: docker push xroier/blart --all-tags \ No newline at end of file diff --git a/BLART/BLART.csproj b/BLART/BLART.csproj index 1b0ce86..e89f6ea 100755 --- a/BLART/BLART.csproj +++ b/BLART/BLART.csproj @@ -1,19 +1,48 @@ - + - Exe - net6.0 + net7.0 enable enable - 2.3.0 - 2.3.0 + 2.4.0 + $(AssemblyVersion) + DefaultContainer + mcr.microsoft.com/dotnet/aspnet:7.0 + $(FileVersion);latest + xroier/blart - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BLART/Bot.cs b/BLART/Bot.cs deleted file mode 100755 index 07ddddc..0000000 --- a/BLART/Bot.cs +++ /dev/null @@ -1,108 +0,0 @@ -namespace BLART; - -using BLART.Commands; -using BLART.Modules; -using BLART.Services; -using Discord; -using Discord.Commands; -using Discord.Interactions; -using Discord.WebSocket; -using Modals; - -public class Bot -{ - private DiscordSocketClient? client; - private SocketGuild? guild; - - public static Bot Instance { get; private set; } = null!; - - public SocketGuild Guild => guild ??= Client.Guilds.FirstOrDefault(g => g.Id == 656673194693885975)!; - public string ReplyEmote => "<:yesexiled:813850607294218251>"; - private DiscordSocketClient Client => client ??= new DiscordSocketClient(new DiscordSocketConfig { GatewayIntents = GatewayIntents.All, AlwaysDownloadUsers = true, MessageCacheSize = 10000, }); - public InteractionService InteractionService { get; private set; } = null!; - public SlashCommandHandler SlashCommandHandler { get; private set; } = null!; - - public Bot(string[] args) - { - Instance = this; - Init(args).GetAwaiter().GetResult(); - } - - /// - /// Terminates the bot. - /// - public void Destroy() => Client.LogoutAsync(); - - private async Task Init(string[] args) - { - try - { - TokenUtils.ValidateToken(TokenType.Bot, Program.Config.BotToken); - } - catch (Exception e) - { - Log.Error(nameof(Init), e); - return; - } - - Log.Debug(nameof(Init), "Initializing Text Commands.."); - - Log.Debug(nameof(Init), "Initializing Slash commands.."); - InteractionService = new InteractionService(Client); - SlashCommandHandler = new SlashCommandHandler(InteractionService, Client); - - Log.Debug(nameof(Init), "Setting up logging.."); - InteractionService.Log += Log.Send; - Client.Log += Log.Send; - Client.MessageDeleted += Logging.OnMessageDeleted; - Client.MessageUpdated += Logging.OnMessageUpdated; - Client.UserJoined += Logging.OnUserJoined; - Client.UserBanned += Logging.OnUserBanned; - Client.UserLeft += Logging.OnUsedLeft; - - Log.Debug(nameof(Init), "Setting up message handlers.."); - Client.MessageReceived += PingTriggers.HandleMessage; - Client.MessageReceived += SpamPrevention.OnMessageReceived; - Client.MessageUpdated += SpamPrevention.OnMessageUpdated; - - Log.Debug(nameof(Init), "Setting up channel renting.."); - Client.UserVoiceStateUpdated += ChannelRenting.OnVoiceStateChanged; - - Log.Debug(nameof(Init), "Setting up raid protection.."); - Client.UserJoined += RaidProtection.OnUserJoined; - - Log.Debug(nameof(Init), "Installing slash commands.."); - await SlashCommandHandler.InstallCommandsAsync(); - Client.Ready += async () => - { - Log.Debug(nameof(Init), "Initializing Database.."); - await DatabaseHandler.Init(args.Contains("--updatetables")); - - int slashCommandsRegistered = (await InteractionService.RegisterCommandsToGuildAsync(Guild.Id)).Count; - - Log.Debug(nameof(Init), $"Registered {slashCommandsRegistered} interaction modules."); - }; - - Log.Debug(nameof(Init), "Registering Modal handlers.."); - Client.ModalSubmitted += BugReportModal.HandleModal; - Client.ModalSubmitted += EmbedModal.HandleModal; - Client.ModalSubmitted += ReportUserModal.HandleModal; - Client.ModalSubmitted += PluginSubmissionModal.HandleModal; - Client.ModalSubmitted += TagModal.HandleModal; - Client.ButtonExecuted += BugReportModal.HandleButton; - Client.ButtonExecuted += EmbedModal.HandleButton; - Client.ButtonExecuted += PluginSubmissionModal.HandleButton; - Client.ButtonExecuted += SyncRolesModal.HandleButton; - Client.ModalSubmitted += Logging.ModalLogging; - Client.ButtonExecuted += Logging.ButtonLogging; - InteractionService.InteractionExecuted += Logging.CommandLogging; - - Log.Debug(nameof(Init), "Logging in.."); - await Client.LoginAsync(TokenType.Bot, Program.Config.BotToken); - await Client.StartAsync(); - - _ = Task.Run(ServerCountUpdater.DoUpdate); - - await Task.Delay(-1); - } -} \ No newline at end of file diff --git a/BLART/Commands/RoleCommands/SyncCommand.cs b/BLART/Commands/RoleCommands/SyncCommand.cs index 222e248..125a09c 100755 --- a/BLART/Commands/RoleCommands/SyncCommand.cs +++ b/BLART/Commands/RoleCommands/SyncCommand.cs @@ -87,7 +87,7 @@ await RespondAsync(embed: await ErrorHandlingService.GetErrorEmbed(ErrorCodes.Un } string dbConn = - $"Server=127.0.0.1;uid={Program.Config.SqlUser};pwd={Program.Config.SqlPassword};database={Program.Config.SqlDatabase};default command timeout=60"; + $"Server={Program.Config.SqlServer};uid={Program.Config.SqlUser};pwd={Program.Config.SqlPassword};database={Program.Config.SqlDatabase};default command timeout=60"; MySqlConnection conn = new(dbConn); conn.Open(); string readText = "SELECT * FROM `credits`"; diff --git a/BLART/Config.cs b/BLART/Config.cs index 50d5d2d..535215c 100755 --- a/BLART/Config.cs +++ b/BLART/Config.cs @@ -15,35 +15,48 @@ public class Config public ulong RedRoleId { get; set; } public ulong BugReportId { get; set; } public int TriggerLengthLimit { get; set; } - public ulong ContributorId { get; set; } = 668651927298375690; + public ulong ContributorId { get; set; } public string NorthwoodApiKey { get; set; } public ulong StaffChannelId { get; set; } public string SqlUser { get; set; } public string SqlPassword { get; set; } public string SqlDatabase { get; set; } + public string SqlServer { get; set; } - public List CreditRoleIds { get; set; } = new(); + public List CreditRoleIds { get; set; } - public static readonly Config Default = new() + public Config() { - BotToken = string.Empty, - BotPrefix = "~", - DiscStaffId = 0, - SpamLimit = 10, - SpamTimeout = 5, - ChannelRentId = 0, - ChannelRentCatId = 0, - LogsId = 0, - Debug = false, - RedRoleId = 0, - BugReportId = 0, - TriggerLengthLimit = 200, - ContributorId = 0, - NorthwoodApiKey = string.Empty, - StaffChannelId = 0, - SqlUser = string.Empty, - SqlPassword = string.Empty, - SqlDatabase = string.Empty, - CreditRoleIds = new(), - }; + BotToken = Environment.GetEnvironmentVariable("BOT_TOKEN")!; + BotPrefix = Environment.GetEnvironmentVariable("BOT_PREFIX")!; + DiscStaffId = ulong.Parse(Environment.GetEnvironmentVariable("DISC_STAFF_ID")!); + SpamLimit = int.Parse(Environment.GetEnvironmentVariable("SPAM_LIMIT")!); + SpamTimeout = int.Parse(Environment.GetEnvironmentVariable("SPAM_TIMEOUT")!); + ChannelRentId = ulong.Parse(Environment.GetEnvironmentVariable("CHANNEL_RENT_ID")!); + ChannelRentCatId = ulong.Parse(Environment.GetEnvironmentVariable("CHANNEL_RENT_CATEGORY_ID")!); + LogsId = ulong.Parse(Environment.GetEnvironmentVariable("LOGS_CHANNEL_ID")!); + Debug = bool.Parse(Environment.GetEnvironmentVariable("DEBUG")!); + RedRoleId = ulong.Parse(Environment.GetEnvironmentVariable("RED_ROLE_ID")!); + BugReportId = ulong.Parse(Environment.GetEnvironmentVariable("BUG_REPORT_CHANNEL_ID")!); + TriggerLengthLimit = int.Parse(Environment.GetEnvironmentVariable("LENGHT_LIMIT")!); + ContributorId = ulong.Parse(Environment.GetEnvironmentVariable("CONTRIBUTOR_ROLE_ID")!); + NorthwoodApiKey = Environment.GetEnvironmentVariable("NW_API_KEY")!; + StaffChannelId = ulong.Parse(Environment.GetEnvironmentVariable("STAFF_CHANNEL_ID")!); + SqlServer = Environment.GetEnvironmentVariable("DB_SERVER")!; + SqlUser = Environment.GetEnvironmentVariable("DB_USER")!; + SqlPassword = Environment.GetEnvironmentVariable("DB_PASSWORD")!; + SqlDatabase = Environment.GetEnvironmentVariable("DB_DATABASE")!; + CreditRoleIds = GetCreditRoleIds().ToList(); + } + + private static IEnumerable GetCreditRoleIds() + { + var env = Environment.GetEnvironmentVariable("CREDIT_ROLE_IDS")!; + var roles = env.Split(','); + foreach (var role in roles) + { + if (ulong.TryParse(role, out ulong returnValue)) + yield return returnValue; + } + } } \ No newline at end of file diff --git a/BLART/Db/BlartDb.cs b/BLART/Db/BlartDb.cs new file mode 100644 index 0000000..491fcb7 --- /dev/null +++ b/BLART/Db/BlartDb.cs @@ -0,0 +1,17 @@ +using BLART.Interfaces; +using LinqToDB; +using LinqToDB.Data; + +namespace BLART.Db; + +public class BlartDb : DataConnection +{ + public BlartDb() : base(nameof(BlartDb)) { } + + public ITable Bans => this.GetTable(); + public ITable PingTriggers => this.GetTable(); + public ITable RedRoles => this.GetTable(); + public ITable SelfAssignableRoles => this.GetTable(); + public ITable Tags => this.GetTable(); + public ITable Warns => this.GetTable(); +} \ No newline at end of file diff --git a/BLART/Interfaces/Ban.cs b/BLART/Interfaces/Ban.cs new file mode 100644 index 0000000..63cd108 --- /dev/null +++ b/BLART/Interfaces/Ban.cs @@ -0,0 +1,23 @@ +using LinqToDB; +using LinqToDB.Mapping; + +namespace BLART.Interfaces; + +[Table("bans")] +public class Ban : IDbTable +{ + [Column("id"), PrimaryKey, Identity] + public ulong Id { get; set; } + + [Column("user_id")] + public ulong UserId { get; set; } + + [Column("staff_id")] + public ulong StaffId { get; set; } + + [Column("reason", DataType = DataType.Text)] + public string Reason { get; set; } = null!; + + [Column("issued_at")] + public DateTimeOffset IssuedAt { get; set; } +} \ No newline at end of file diff --git a/BLART/Interfaces/IDbTable.cs b/BLART/Interfaces/IDbTable.cs new file mode 100644 index 0000000..7264690 --- /dev/null +++ b/BLART/Interfaces/IDbTable.cs @@ -0,0 +1,4 @@ +namespace BLART.Interfaces; + +// Just to register tables more easily. +public interface IDbTable { } \ No newline at end of file diff --git a/BLART/Interfaces/PingTrigger.cs b/BLART/Interfaces/PingTrigger.cs new file mode 100644 index 0000000..ac870f9 --- /dev/null +++ b/BLART/Interfaces/PingTrigger.cs @@ -0,0 +1,14 @@ +using LinqToDB; +using LinqToDB.Mapping; + +namespace BLART.Interfaces; + +[Table("ping_triggers")] +public class PingTrigger : IDbTable +{ + [Column("user_id"), PrimaryKey] + public ulong UserId { get; set; } + + [Column("message", DataType = DataType.Text)] + public string Message { get; set; } = null!; +} \ No newline at end of file diff --git a/BLART/Interfaces/RedRole.cs b/BLART/Interfaces/RedRole.cs new file mode 100644 index 0000000..0a0f967 --- /dev/null +++ b/BLART/Interfaces/RedRole.cs @@ -0,0 +1,23 @@ +using LinqToDB; +using LinqToDB.Mapping; + +namespace BLART.Interfaces; + +[Table("red_roles")] +public class RedRole : IDbTable +{ + [Column("id"), PrimaryKey, Identity] + public ulong Id { get; set; } + + [Column("user_id")] + public ulong UserId { get; set; } + + [Column("staff_id")] + public ulong StaffId { get; set; } + + [Column("reason", DataType = DataType.Text)] + public string Reason { get; set; } = null!; + + [Column("issued_at")] + public DateTimeOffset IssuedAt { get; set; } +} \ No newline at end of file diff --git a/BLART/Interfaces/SelfAssignableRole.cs b/BLART/Interfaces/SelfAssignableRole.cs new file mode 100644 index 0000000..6ad6589 --- /dev/null +++ b/BLART/Interfaces/SelfAssignableRole.cs @@ -0,0 +1,10 @@ +using LinqToDB.Mapping; + +namespace BLART.Interfaces; + +[Table("self_assignable_roles")] +public class SelfAssignableRole : IDbTable +{ + [Column("role_id"), PrimaryKey] + public ulong RoleId { get; set; } +} \ No newline at end of file diff --git a/BLART/Interfaces/Tag.cs b/BLART/Interfaces/Tag.cs new file mode 100644 index 0000000..73718d7 --- /dev/null +++ b/BLART/Interfaces/Tag.cs @@ -0,0 +1,17 @@ +using LinqToDB; +using LinqToDB.Mapping; + +namespace BLART.Interfaces; + +[Table("tags")] +public class Tag : IDbTable +{ + [Column("name", DataType = DataType.Text), PrimaryKey] + public string Name { get; set; } = null!; + + [Column("text", DataType = DataType.Text)] + public string Text { get; set; } = null!; + + [Column("user_id")] + public ulong UserId { get; set; } +} \ No newline at end of file diff --git a/BLART/Interfaces/Warn.cs b/BLART/Interfaces/Warn.cs new file mode 100644 index 0000000..9c0f1f1 --- /dev/null +++ b/BLART/Interfaces/Warn.cs @@ -0,0 +1,23 @@ +using LinqToDB; +using LinqToDB.Mapping; + +namespace BLART.Interfaces; + +[Table("warns")] +public class Warn : IDbTable +{ + [Column("id"), PrimaryKey, Identity] + public ulong Id { get; set; } + + [Column("user_id")] + public ulong UserId { get; set; } + + [Column("staff_id")] + public ulong StaffId { get; set; } + + [Column("reason", DataType = DataType.Text)] + public string Reason { get; set; } = null!; + + [Column("issued_at")] + public DateTimeOffset IssuedAt { get; set; } +} \ No newline at end of file diff --git a/BLART/Modules/PingTriggers.cs b/BLART/Modules/PingTriggers.cs index ef686f9..0c209fe 100755 --- a/BLART/Modules/PingTriggers.cs +++ b/BLART/Modules/PingTriggers.cs @@ -7,7 +7,7 @@ namespace BLART.Modules; public class PingTriggers { - private static ConcurrentDictionary _lastPing { get; } = new(); + private static ConcurrentDictionary LastPing { get; } = new(); public static async Task HandleMessage(SocketMessage msg) { @@ -16,20 +16,16 @@ public static async Task HandleMessage(SocketMessage msg) try { - if (_lastPing.ContainsKey(msg.Author) && (DateTime.UtcNow - _lastPing[msg.Author]).TotalMinutes < 2) - { - Log.Debug($"{nameof(Log)}.{nameof(HandleMessage)}", - $"Last ping too recent, returning. {_lastPing[msg.Author]} {(DateTime.UtcNow - _lastPing[msg.Author]).TotalMinutes}"); + if (LastPing.TryGetValue(msg.Author, out DateTime value) && (DateTime.UtcNow - value).TotalMinutes < 2) return; - } - + foreach (SocketUser mentioned in msg.MentionedUsers) { string triggerMessage = DatabaseHandler.GetPingTrigger(mentioned.Id); if (!string.IsNullOrEmpty(triggerMessage) && triggerMessage.Length < Program.Config.TriggerLengthLimit) { await msg.Channel.SendMessageAsync(embed: await EmbedBuilderService.CreateBasicEmbed("Ping Trigger", $"{msg.Author.Mention} - {triggerMessage}", Color.Gold)); - _lastPing[msg.Author] = DateTime.UtcNow; + LastPing[msg.Author] = DateTime.UtcNow; break; } } diff --git a/BLART/Modules/SpamPrevention.cs b/BLART/Modules/SpamPrevention.cs index afedba5..ba63d19 100755 --- a/BLART/Modules/SpamPrevention.cs +++ b/BLART/Modules/SpamPrevention.cs @@ -1,3 +1,5 @@ +using BLART.Services; + namespace BLART.Modules; using System.Text; diff --git a/BLART/Modules/TimeParsing.cs b/BLART/Modules/TimeParsing.cs index 144c276..8273540 100755 --- a/BLART/Modules/TimeParsing.cs +++ b/BLART/Modules/TimeParsing.cs @@ -25,24 +25,16 @@ public static TimeSpan ParseDuration(string duration) public static TimeSpan FromChar(char c, int duration) { - switch (c) + return c switch { - case 's': - return TimeSpan.FromSeconds(duration); - case 'm': - return TimeSpan.FromMinutes(duration); - case 'h': - return TimeSpan.FromHours(duration); - case 'd': - return TimeSpan.FromDays(duration); - case 'w': - return TimeSpan.FromDays(duration * 7); - case 'M': - return TimeSpan.FromDays(duration * 30); - case 'y': - return TimeSpan.FromDays(duration * 365); - default: - return TimeSpan.MinValue; - } + 's' => TimeSpan.FromSeconds(duration), + 'm' => TimeSpan.FromMinutes(duration), + 'h' => TimeSpan.FromHours(duration), + 'd' => TimeSpan.FromDays(duration), + 'w' => TimeSpan.FromDays(duration * 7), + 'M' => TimeSpan.FromDays(duration * 30), + 'y' => TimeSpan.FromDays(duration * 365), + _ => TimeSpan.MinValue + }; } } \ No newline at end of file diff --git a/BLART/Program.cs b/BLART/Program.cs index 2426796..4ad376a 100755 --- a/BLART/Program.cs +++ b/BLART/Program.cs @@ -1,33 +1,37 @@ -namespace BLART; +using BLART; +using BLART.Services; +using Serilog; -using System.Reflection; -using System.Runtime.CompilerServices; -using Newtonsoft.Json; +var builder = WebApplication.CreateBuilder(); -public static class Program + +var host = Host.CreateDefaultBuilder(args) + .ConfigureLogging(logging => + { + var logger = new LoggerConfiguration().WriteTo.Console().CreateLogger(); + logging.ClearProviders().AddSerilog(logger); + }) + .ConfigureServices(services => + { + services.AddSingleton(); + services.AddHostedService(); + services.AddSingleton(); + services.AddHostedService(); + }) + .Build(); + +/*public static class Program { - private static Config? _config; - private static string KCfgFile = "Blart.json"; private static Bot? _bot; public static string DatabaseFile { get; } = Path.Combine(Environment.CurrentDirectory, "Blart.db"); - public static Config Config => _config ??= GetConfig(); + public static Config Config => Config.Default; public static Random Rng { get; } = new(); public static void Main(string[] args) { Console.WriteLine($"Starting. Version: {Assembly.GetExecutingAssembly().GetName().Version}"); - if (args.Contains("--debug")) - Config.Debug = true; _bot = new Bot(args); AppDomain.CurrentDomain.ProcessExit += (_, _) => _bot.Destroy(); } - - private static Config GetConfig() - { - if (File.Exists(KCfgFile)) - return JsonConvert.DeserializeObject(File.ReadAllText(KCfgFile))!; - File.WriteAllText(KCfgFile, JsonConvert.SerializeObject(Config.Default, Formatting.Indented)); - return Config.Default; - } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/BLART/Services/Bot.cs b/BLART/Services/Bot.cs new file mode 100644 index 0000000..f07185b --- /dev/null +++ b/BLART/Services/Bot.cs @@ -0,0 +1,113 @@ +using BLART.Commands; +using BLART.Modals; +using BLART.Modules; +using Discord; +using Discord.Interactions; +using Discord.WebSocket; + +namespace BLART.Services; + +public class Bot : BackgroundService +{ + private DiscordSocketClient? _client; + private SocketGuild? _guild; + private readonly ILogger _logger; + private readonly Config _config; + + public Bot(ILogger logger, Config config) + { + _logger = logger; + _config = config; + } + + public SocketGuild Guild => _guild ??= Client.Guilds.FirstOrDefault(g => g.Id == 656673194693885975)!; + public string ReplyEmote => "<:yesexiled:813850607294218251>"; + private DiscordSocketClient Client => _client ??= new DiscordSocketClient(new DiscordSocketConfig { GatewayIntents = GatewayIntents.All, AlwaysDownloadUsers = true, MessageCacheSize = 10000, }); + private InteractionService InteractionService { get; set; } = null!; + private SlashCommandHandler SlashCommandHandler { get; set; } = null!; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + try + { + TokenUtils.ValidateToken(TokenType.Bot, _config.BotToken); + } + catch (Exception e) + { + _logger.LogError(e, "Token validation failed"); + return; + } + + InteractionService = new InteractionService(Client); + SlashCommandHandler = new SlashCommandHandler(InteractionService, Client); + + InteractionService.Log += Log; + Client.Log += Log; + Client.MessageDeleted += Logging.OnMessageDeleted; + Client.MessageUpdated += Logging.OnMessageUpdated; + Client.UserJoined += Logging.OnUserJoined; + Client.UserBanned += Logging.OnUserBanned; + Client.UserLeft += Logging.OnUsedLeft; + + + Client.MessageReceived += PingTriggers.HandleMessage; + Client.MessageReceived += SpamPrevention.OnMessageReceived; + Client.MessageUpdated += SpamPrevention.OnMessageUpdated; + + + Client.UserVoiceStateUpdated += ChannelRenting.OnVoiceStateChanged; + + + Client.UserJoined += RaidProtection.OnUserJoined; + + + await SlashCommandHandler.InstallCommandsAsync(); + + Client.ModalSubmitted += BugReportModal.HandleModal; + Client.ModalSubmitted += EmbedModal.HandleModal; + Client.ModalSubmitted += ReportUserModal.HandleModal; + Client.ModalSubmitted += PluginSubmissionModal.HandleModal; + Client.ModalSubmitted += TagModal.HandleModal; + Client.ButtonExecuted += BugReportModal.HandleButton; + Client.ButtonExecuted += EmbedModal.HandleButton; + Client.ButtonExecuted += PluginSubmissionModal.HandleButton; + Client.ButtonExecuted += SyncRolesModal.HandleButton; + Client.ModalSubmitted += Logging.ModalLogging; + Client.ButtonExecuted += Logging.ButtonLogging; + InteractionService.InteractionExecuted += Logging.CommandLogging; + + await Client.LoginAsync(TokenType.Bot, _config.BotToken); + await Client.StartAsync(); + + await Task.Delay(-1, stoppingToken); + } + + private Task Log(LogMessage arg) + { + switch (arg.Severity) + { + case LogSeverity.Critical: + case LogSeverity.Error: + _logger.LogError(arg.Exception, "{Message}", arg.Message); + break; + case LogSeverity.Warning: + _logger.LogWarning("{Message}", arg.Message); + break; + case LogSeverity.Info: + _logger.LogInformation("{Message}", arg.Message); + break; + case LogSeverity.Verbose: + case LogSeverity.Debug: + _logger.LogDebug("{Message}", arg.Message); + break; + } + + return Task.CompletedTask; + } + + public override async Task StopAsync(CancellationToken cancellationToken) + { + await Client.LogoutAsync(); + await base.StopAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/BLART/Services/DbInitService.cs b/BLART/Services/DbInitService.cs new file mode 100644 index 0000000..f759cf0 --- /dev/null +++ b/BLART/Services/DbInitService.cs @@ -0,0 +1,35 @@ +using BLART.Db; +using BLART.Interfaces; +using LinqToDB; + +namespace BLART.Services; + +public class DbInitService : BackgroundService +{ + private readonly ILogger _logger; + + public DbInitService(ILogger logger) + { + _logger = logger; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + var assembly = typeof(Program).Assembly; + var tableTypes = assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IDbTable))).ToList(); + + using (var db = new BlartDb()) + { + var existingTables = db.DataProvider.GetSchemaProvider().GetSchema(db).Tables; + foreach (var tableType in tableTypes) + { + if (existingTables.All(t => t.TableName != (string?)tableType.GetProperty("TableName")?.GetValue(tableType))) + { + typeof(DataExtensions) + .GetMethod(nameof(DataExtensions.CreateTable), new[] { typeof(BlartDb) }) + ?.MakeGenericMethod(tableType).Invoke(null, new object?[] { db }); + } + } + } + } +} \ No newline at end of file diff --git a/BLART/Services/Log.cs b/BLART/Services/Log.cs deleted file mode 100755 index 6f67162..0000000 --- a/BLART/Services/Log.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace BLART.Services; - -using Discord; - -public class Log -{ - public static Task Send(LogMessage msg) - { - Console.WriteLine(msg.ToString()); - return Task.CompletedTask; - } - - public static void Info(string source, object msg) => Send(new LogMessage(LogSeverity.Info, - source, msg.ToString())); - - public static void Debug(string source, object msg) - { - if (Program.Config.Debug) - Send(new LogMessage(LogSeverity.Debug, source, msg.ToString())); - } - - public static void Error(string source, object msg) => Send(new LogMessage(LogSeverity.Error, source, msg.ToString())); - - public static void Warn(string source, object msg) => - Send(new LogMessage(LogSeverity.Warning, source, msg.ToString())); -} \ No newline at end of file diff --git a/BLART/appsettings.Development.json b/BLART/appsettings.Development.json new file mode 100644 index 0000000..b2dcdb6 --- /dev/null +++ b/BLART/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/BLART/appsettings.json b/BLART/appsettings.json new file mode 100644 index 0000000..b2dcdb6 --- /dev/null +++ b/BLART/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/README.md b/README.md index 29a9a86..0908aee 100755 --- a/README.md +++ b/README.md @@ -1 +1,64 @@ # BLART + +[![Docker Pulls](https://img.shields.io/docker/pulls/xroier/blart)](https://hub.docker.com/r/xroier/blart/) +### BLART is the official moderating and utils bot for EXILED. + +# Running on Docker + +Those are the instructions on how to run the `xroier/blart` Docker image with the specified environment variables. The image requires the following environment variables to be set: + +- `DB_SERVER`: The database server address. +- `DB_DATABASE`: The name of the database to connect to. +- `DB_USER`: The username for the database connection. +- `DB_PASSWORD`: The password for the database connection. +- `BOT_TOKEN`: The token for your bot. +- `BOT_PREFIX`: The prefix for bot commands (default is "~"). +- `DISC_STAFF_ID`: The Discord staff ID. +- `SPAM_LIMIT`: The spam message limit. +- `SPAM_TIMEOUT`: The spam timeout in minutes. +- `CHANNEL_RENT_ID`: The ID of the voice rent channel. +- `CHANNEL_RENT_CATEGORY_ID`: The ID of the voice rent category. +- `LOGS_CHANNEL_ID`: The ID of the logs channel. +- `DEBUG`: Set to "true" for debug mode, or "false" to disable debug. +- `RED_ROLE_ID`: The ID of the red role. +- `BUG_REPORT_CHANNEL_ID`: The ID of the bug report channel. +- `LENGHT_LIMIT`: The character length limit for ping triggers. +- `CONTRIBUTOR_ROLE_ID`: The ID of the contributor role. +- `NW_API_KEY`: The API key for northwood api requests. +- `STAFF_CHANNEL_ID`: The ID of the staff channel. +- `CREDIT_ROLE_IDS`: Comma-separated IDs for credit roles. + +Make sure you have Docker installed on your system before proceeding. + +## Running the Docker Container + +To run the `xroier/blart` Docker container with the specified environment variables, you can use the following `docker run` command. Replace the placeholders with the actual values for your environment: + +```bash +docker run -d \ + -e DB_SERVER= \ + -e DB_DATABASE= \ + -e DB_USER= \ + -e DB_PASSWORD= \ + -e BOT_TOKEN= \ + -e BOT_PREFIX= \ + -e DISC_STAFF_ID= \ + -e SPAM_LIMIT= \ + -e SPAM_TIMEOUT= \ + -e CHANNEL_RENT_ID= \ + -e CHANNEL_RENT_CATEGORY_ID= \ + -e LOGS_CHANNEL_ID= \ + -e DEBUG= \ + -e RED_ROLE_ID= \ + -e BUG_REPORT_CHANNEL_ID= \ + -e LENGHT_LIMIT= \ + -e CONTRIBUTOR_ROLE_ID= \ + -e NW_API_KEY= \ + -e STAFF_CHANNEL_ID= \ + -e CREDIT_ROLE_IDS= \ + docker.io/xroier/blart +``` + +Replace ``, ``, ``, and so on with your specific values for each environment variable. + +After running the command, the Docker container will start with the specified environment variables, and the `xroier/blart` application will use these settings. \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 0000000..7cd6a1f --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "7.0.0", + "rollForward": "latestMajor", + "allowPrerelease": true + } +} \ No newline at end of file