From 50a2c936cc3f5d3fa7f479781ff79ed0985662e7 Mon Sep 17 00:00:00 2001 From: Sella-GH <147769367+Sella-GH@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:23:33 +0200 Subject: [PATCH] Rename and move some database stuff, also prepare for rework of Updater --- .../AzuraCastMountAutocomplete.cs | 4 +- AzzyBot-Next/Commands/ConfigCommands.cs | 40 +++++++--- AzzyBot-Next/Database/AzzyDbContext.cs | 6 +- AzzyBot-Next/Database/DbActions.cs | 80 ++++++++++++------- .../Entities/AzuraCastChecksEntity.cs | 5 +- .../Database/Entities/AzuraCastEntity.cs | 1 + .../Entities/AzuraCastStationChecksEntity.cs | 15 ++++ .../Entities/AzuraCastStationEntity.cs | 4 +- ...tity.cs => AzuraCastStationMountEntity.cs} | 2 +- AzzyBot-Next/Logging/LoggerActions.cs | 2 +- ...0240610192325_InitialCreation.Designer.cs} | 80 ++++++++++++++----- ...n.cs => 20240610192325_InitialCreation.cs} | 62 ++++++++++---- .../Migrations/AzzyDbContextModelSnapshot.cs | 78 +++++++++++++----- .../Services/Modules/AzuraCastFileService.cs | 4 +- AzzyBot-Next/Services/UpdaterService.cs | 41 +++++++++- AzzyBot-Next/Utilities/EmbedBuilder.cs | 4 +- 16 files changed, 311 insertions(+), 117 deletions(-) create mode 100644 AzzyBot-Next/Database/Entities/AzuraCastStationChecksEntity.cs rename AzzyBot-Next/Database/Entities/{AzuraCastMountEntity.cs => AzuraCastStationMountEntity.cs} (90%) rename AzzyBot-Next/Migrations/{20240609204920_InitialCreation.Designer.cs => 20240610192325_InitialCreation.Designer.cs} (85%) rename AzzyBot-Next/Migrations/{20240609204920_InitialCreation.cs => 20240610192325_InitialCreation.cs} (84%) diff --git a/AzzyBot-Next/Commands/Autocompletes/AzuraCastMountAutocomplete.cs b/AzzyBot-Next/Commands/Autocompletes/AzuraCastMountAutocomplete.cs index 24abd644..97df0059 100644 --- a/AzzyBot-Next/Commands/Autocompletes/AzuraCastMountAutocomplete.cs +++ b/AzzyBot-Next/Commands/Autocompletes/AzuraCastMountAutocomplete.cs @@ -25,10 +25,10 @@ public async ValueTask> AutoCompleteAsync(Au if (stationId == 0) return new Dictionary(); - List mountsInDb = await _dbActions.GetAzuraCastMountsAsync(context.Guild.Id, stationId); + List mountsInDb = await _dbActions.GetAzuraCastStationMountsAsync(context.Guild.Id, stationId); Dictionary results = []; - foreach (AzuraCastMountEntity mount in mountsInDb) + foreach (AzuraCastStationMountEntity mount in mountsInDb) { results.Add(Crypto.Decrypt(mount.Name), mount.Id); } diff --git a/AzzyBot-Next/Commands/ConfigCommands.cs b/AzzyBot-Next/Commands/ConfigCommands.cs index b64766fd..6bff3b97 100644 --- a/AzzyBot-Next/Commands/ConfigCommands.cs +++ b/AzzyBot-Next/Commands/ConfigCommands.cs @@ -33,7 +33,10 @@ public async ValueTask AddAzuraCastAsync [Description("Set the base Url, an example: https://demo.azuracast.com/")] Uri url, [Description("Add an administrator api key. It's enough when it has the permission to access system information.")] string apiKey, [Description("Select a channel to get general notifications about your azuracast installation."), ChannelTypes(DiscordChannelType.Text)] DiscordChannel notificationChannel, - [Description("Select a channel to get notifications when your azuracast installation is down."), ChannelTypes(DiscordChannelType.Text)] DiscordChannel outagesChannel + [Description("Select a channel to get notifications when your azuracast installation is down."), ChannelTypes(DiscordChannelType.Text)] DiscordChannel outagesChannel, + [Description("Enable or disable the automatic check if the AzuraCast instance of your server is down.")] bool serverStatus, + [Description("Enable or disable the automatic check for AzuraCast updates.")] bool updates, + [Description("Enable or disable the addition of the changelog to the posted AzuraCast updates.")] bool updatesChangelog ) { ArgumentNullException.ThrowIfNull(context, nameof(context)); @@ -62,7 +65,7 @@ public async ValueTask AddAzuraCastAsync return; } - await _db.AddAzuraCastAsync(guildId, url, apiKey, notificationChannel.Id, outagesChannel.Id); + await _db.AddAzuraCastAsync(guildId, url, apiKey, notificationChannel.Id, outagesChannel.Id, serverStatus, updates, updatesChangelog); await context.DeleteResponseAsync(); await context.FollowupAsync("Your AzuraCast installation was added successfully and your data has been encrypted."); @@ -84,7 +87,7 @@ public async ValueTask AddAzuraCastMountAsync await context.DeferResponseAsync(); ulong guildId = context.Guild?.Id ?? throw new InvalidOperationException("Guild is null"); - await _db.AddAzuraCastMountPointAsync(guildId, station, mountName, mount); + await _db.AddAzuraCastStationMountPointAsync(guildId, station, mountName, mount); await context.EditResponseAsync("Your mount point was added successfully."); } @@ -99,9 +102,6 @@ public async ValueTask AddAzuraCastStationAsync [Description("Enable or disable the preference of HLS streams if you add an able mount point.")] bool hls, [Description("Enable or disable the showing of the playlist in the nowplaying embed.")] bool showPlaylist, [Description("Enable or disable the automatic check if files have been changed.")] bool fileChanges, - [Description("Enable or disable the automatic check if the AzuraCast instance of your server is down.")] bool serverStatus, - [Description("Enable or disable the automatic check for AzuraCast updates.")] bool updates, - [Description("Enable or disable the addition of the changelog to the posted AzuraCast updates.")] bool updatesChangelog, [Description("Enter the api key of the new station. This is optional if the admin one has the permission.")] string? apiKey = null ) { @@ -118,7 +118,7 @@ public async ValueTask AddAzuraCastStationAsync await context.DeferResponseAsync(); ulong guildId = context.Guild?.Id ?? throw new InvalidOperationException("Guild is null"); - await _db.AddAzuraCastStationAsync(guildId, station, stationName, requestsChannel.Id, hls, showPlaylist, fileChanges, serverStatus, updates, updatesChangelog, apiKey); + await _db.AddAzuraCastStationAsync(guildId, station, stationName, requestsChannel.Id, hls, showPlaylist, fileChanges, apiKey); await context.DeleteResponseAsync(); await context.FollowupAsync("Your station was added successfully. Your station name and api key have been encrypted. Your request was also deleted for security reasons."); @@ -201,12 +201,10 @@ public async ValueTask UpdateAzuraCastAsync await context.FollowupAsync("Your AzuraCast settings were saved successfully and have been encrypted."); } - [Command("modify-azuracast-checks"), Description("Configure the automatic checks inside a station.")] + [Command("modify-azuracast-checks"), Description("Configure the automatic checks for your AzuraCast installation.")] public async ValueTask UpdateAzuraCastChecksAsync ( CommandContext context, - [Description("Choose the station you want to modify the checks."), SlashAutoCompleteProvider] int station, - [Description("Enable or disable the automatic check if files have been changed.")] bool? fileChanges = null, [Description("Enable or disable the automatic check if the AzuraCast instance of your server is down.")] bool? serverStatus = null, [Description("Enable or disable the automatic check for AzuraCast updates.")] bool? updates = null, [Description("Enable or disable the addition of the changelog to the posted AzuraCast updates.")] bool? updatesChangelog = null @@ -219,7 +217,7 @@ public async ValueTask UpdateAzuraCastChecksAsync await context.DeferResponseAsync(); ulong guildId = context.Guild?.Id ?? throw new InvalidOperationException("Guild is null"); - await _db.UpdateAzuraCastChecksAsync(guildId, station, fileChanges, serverStatus, updates, updatesChangelog); + await _db.UpdateAzuraCastChecksAsync(guildId, serverStatus, updates, updatesChangelog); await context.EditResponseAsync("Your settings were saved successfully."); } @@ -250,6 +248,26 @@ public async ValueTask UpdateAzuraCastStationAsync await context.FollowupAsync("Your settings were saved successfully. Your station name and api key have been encrypted. Your request was also deleted for security reasons."); } + [Command("modify-azuracast-station-checks"), Description("Configure the automatic checks inside a station.")] + public async ValueTask UpdateAzuraCastChecksAsync + ( + CommandContext context, + [Description("Choose the station you want to modify the checks."), SlashAutoCompleteProvider] int station, + [Description("Enable or disable the automatic check if files have been changed.")] bool? fileChanges = null + ) + { + ArgumentNullException.ThrowIfNull(context, nameof(context)); + + _logger.CommandRequested(nameof(UpdateAzuraCastChecksAsync), context.User.GlobalName); + + await context.DeferResponseAsync(); + + ulong guildId = context.Guild?.Id ?? throw new InvalidOperationException("Guild is null"); + await _db.UpdateAzuraCastStationChecksAsync(guildId, station, fileChanges); + + await context.EditResponseAsync("Your settings were saved successfully."); + } + [Command("modify-core")] public async ValueTask UpdateCoreAsync(CommandContext context, [Description("Select a channel to get notifications when the bot runs into an issue."), ChannelTypes(DiscordChannelType.Text)] DiscordChannel? errorChannel = null) { diff --git a/AzzyBot-Next/Database/AzzyDbContext.cs b/AzzyBot-Next/Database/AzzyDbContext.cs index 8ca33467..b371dde1 100644 --- a/AzzyBot-Next/Database/AzzyDbContext.cs +++ b/AzzyBot-Next/Database/AzzyDbContext.cs @@ -16,9 +16,10 @@ public AzzyDbContext(DbContextOptions options) : base(options) public DbSet Guilds { get; set; } public DbSet AzuraCast { get; set; } - public DbSet AzuraCastStations { get; set; } public DbSet AzuraCastChecks { get; set; } - public DbSet AzuraCastMounts { get; set; } + public DbSet AzuraCastStations { get; set; } + public DbSet AzuraCastStationChecks { get; set; } + public DbSet AzuraCastMounts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -26,6 +27,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().Navigation(g => g.AzuraCast).AutoInclude(); modelBuilder.Entity().Navigation(a => a.Stations).AutoInclude(); + modelBuilder.Entity().Navigation(a => a.Checks).AutoInclude(); modelBuilder.Entity().Navigation(s => s.Checks).AutoInclude(); modelBuilder.Entity().Navigation(s => s.Mounts).AutoInclude(); diff --git a/AzzyBot-Next/Database/DbActions.cs b/AzzyBot-Next/Database/DbActions.cs index a146bd06..9f4dca11 100644 --- a/AzzyBot-Next/Database/DbActions.cs +++ b/AzzyBot-Next/Database/DbActions.cs @@ -41,7 +41,7 @@ private async Task ExecuteDbActionAsync(Func action) } } - public Task AddAzuraCastAsync(ulong guildId, Uri baseUrl, string apiKey, ulong notificationId, ulong outagesId) + public Task AddAzuraCastAsync(ulong guildId, Uri baseUrl, string apiKey, ulong notificationId, ulong outagesId, bool serverStatus, bool updates, bool changelog) { ArgumentNullException.ThrowIfNull(baseUrl, nameof(baseUrl)); @@ -58,6 +58,14 @@ public Task AddAzuraCastAsync(ulong guildId, Uri baseUrl, string apiKey, u GuildId = guild.Id }; + azuraCast.Checks = new() + { + ServerStatus = serverStatus, + Updates = updates, + UpdatesShowChangelog = changelog, + AzuraCastId = azuraCast.Id + }; + guild.AzuraCastSet = true; await context.AzuraCast.AddAsync(azuraCast); @@ -65,7 +73,7 @@ public Task AddAzuraCastAsync(ulong guildId, Uri baseUrl, string apiKey, u }); } - public Task AddAzuraCastStationAsync(ulong guildId, int stationId, string name, ulong requestsId, bool hls, bool showPlaylist, bool fileChanges, bool serverStatus, bool updates, bool updatesChangelog, string? apiKey) + public Task AddAzuraCastStationAsync(ulong guildId, int stationId, string name, ulong requestsId, bool hls, bool showPlaylist, bool fileChanges, string? apiKey) { return ExecuteDbActionAsync(async context => { @@ -85,9 +93,6 @@ public Task AddAzuraCastStationAsync(ulong guildId, int stationId, string station.Checks = new() { FileChanges = fileChanges, - ServerStatus = serverStatus, - Updates = updates, - UpdatesShowChangelog = updatesChangelog, StationId = station.Id }; @@ -95,13 +100,13 @@ public Task AddAzuraCastStationAsync(ulong guildId, int stationId, string }); } - public Task AddAzuraCastMountPointAsync(ulong guildId, int stationId, string mountName, string mount) + public Task AddAzuraCastStationMountPointAsync(ulong guildId, int stationId, string mountName, string mount) { return ExecuteDbActionAsync(async context => { AzuraCastStationEntity station = await GetAzuraCastStationAsync(guildId, stationId); - AzuraCastMountEntity mountPoint = new() + AzuraCastStationMountEntity mountPoint = new() { Name = Crypto.Encrypt(mountName), Mount = Crypto.Encrypt(mount), @@ -147,7 +152,7 @@ public Task DeleteAzuraCastMountAsync(ulong guildId, int stationId, int mo { return ExecuteDbActionAsync(async context => { - AzuraCastMountEntity mount = await GetAzuraCastMountAsync(guildId, stationId, mountId); + AzuraCastStationMountEntity mount = await GetAzuraCastStationMountAsync(guildId, stationId, mountId); context.AzuraCastMounts.Remove(mount); }); @@ -183,39 +188,46 @@ public async Task GetAzuraCastAsync(ulong guildId) return guild.AzuraCast ?? throw new InvalidOperationException("AzuraCast settings not found in databse"); } - public async Task GetAzuraCastChecksAsync(ulong guildId, int stationId) + public async Task GetAzuraCastChecksAsync(ulong guildId) { - AzuraCastStationEntity station = await GetAzuraCastStationAsync(guildId, stationId); + AzuraCastEntity azuraCast = await GetAzuraCastAsync(guildId); - return station.Checks; + return azuraCast.Checks; } - public async Task GetAzuraCastMountAsync(ulong guildId, int stationId, int mountId) + public async Task GetAzuraCastStationAsync(ulong guildId, int stationId) { - AzuraCastStationEntity station = await GetAzuraCastStationAsync(guildId, stationId); + AzuraCastEntity azuraCast = await GetAzuraCastAsync(guildId); - return station.Mounts.FirstOrDefault(m => m.Id == mountId) ?? throw new InvalidOperationException("Mount not found in database"); + return azuraCast.Stations.FirstOrDefault(s => s.StationId == stationId) ?? throw new InvalidOperationException("Station not found in database"); + } + + public async Task> GetAzuraCastStationsAsync(ulong guildId) + { + AzuraCastEntity azuraCast = await GetAzuraCastAsync(guildId); + + return [.. azuraCast.Stations]; } - public async Task> GetAzuraCastMountsAsync(ulong guildId, int stationId) + public async Task GetAzuraCastStationChecksAsync(ulong guildId, int stationId) { AzuraCastStationEntity station = await GetAzuraCastStationAsync(guildId, stationId); - return [.. station.Mounts]; + return station.Checks; } - public async Task GetAzuraCastStationAsync(ulong guildId, int stationId) + public async Task GetAzuraCastStationMountAsync(ulong guildId, int stationId, int mountId) { - AzuraCastEntity azuraCast = await GetAzuraCastAsync(guildId); + AzuraCastStationEntity station = await GetAzuraCastStationAsync(guildId, stationId); - return azuraCast.Stations.FirstOrDefault(s => s.StationId == stationId) ?? throw new InvalidOperationException("Station not found in database"); + return station.Mounts.FirstOrDefault(m => m.Id == mountId) ?? throw new InvalidOperationException("Mount not found in database"); } - public async Task> GetAzuraCastStationsAsync(ulong guildId) + public async Task> GetAzuraCastStationMountsAsync(ulong guildId, int stationId) { - AzuraCastEntity azuraCast = await GetAzuraCastAsync(guildId); + AzuraCastStationEntity station = await GetAzuraCastStationAsync(guildId, stationId); - return [.. azuraCast.Stations]; + return [.. station.Mounts]; } public async Task GetGuildAsync(ulong guildId) @@ -263,14 +275,11 @@ public Task UpdateAzuraCastAsync(ulong guildId, Uri? baseUrl, string? apiK }); } - public Task UpdateAzuraCastChecksAsync(ulong guildId, int stationId, bool? fileChanges, bool? serverStatus, bool? updates, bool? updatesChangelog) + public Task UpdateAzuraCastChecksAsync(ulong guildId, bool? serverStatus, bool? updates, bool? changelog) { return ExecuteDbActionAsync(async context => { - AzuraCastChecksEntity checks = await GetAzuraCastChecksAsync(guildId, stationId); - - if (fileChanges.HasValue) - checks.FileChanges = fileChanges.Value; + AzuraCastChecksEntity checks = await GetAzuraCastChecksAsync(guildId); if (serverStatus.HasValue) checks.ServerStatus = serverStatus.Value; @@ -278,8 +287,8 @@ public Task UpdateAzuraCastChecksAsync(ulong guildId, int stationId, bool? if (updates.HasValue) checks.Updates = updates.Value; - if (updatesChangelog.HasValue) - checks.UpdatesShowChangelog = updatesChangelog.Value; + if (changelog.HasValue) + checks.UpdatesShowChangelog = changelog.Value; context.AzuraCastChecks.Update(checks); }); @@ -313,6 +322,19 @@ public Task UpdateAzuraCastStationAsync(ulong guildId, int station, int? s }); } + public Task UpdateAzuraCastStationChecksAsync(ulong guildId, int stationId, bool? fileChanges) + { + return ExecuteDbActionAsync(async context => + { + AzuraCastStationChecksEntity checks = await GetAzuraCastStationChecksAsync(guildId, stationId); + + if (fileChanges.HasValue) + checks.FileChanges = fileChanges.Value; + + context.AzuraCastStationChecks.Update(checks); + }); + } + public Task UpdateGuildAsync(ulong guildId, ulong? errorChannelId, bool? isDebug) { return ExecuteDbActionAsync(async context => diff --git a/AzzyBot-Next/Database/Entities/AzuraCastChecksEntity.cs b/AzzyBot-Next/Database/Entities/AzuraCastChecksEntity.cs index e56afa87..5f4cce6e 100644 --- a/AzzyBot-Next/Database/Entities/AzuraCastChecksEntity.cs +++ b/AzzyBot-Next/Database/Entities/AzuraCastChecksEntity.cs @@ -7,11 +7,10 @@ public sealed class AzuraCastChecksEntity { public int Id { get; set; } - public bool FileChanges { get; set; } public bool ServerStatus { get; set; } public bool Updates { get; set; } public bool UpdatesShowChangelog { get; set; } - public int StationId { get; set; } - public AzuraCastStationEntity Station { get; set; } = null!; + public int AzuraCastId { get; set; } + public AzuraCastEntity AzuraCast { get; set; } = null!; } diff --git a/AzzyBot-Next/Database/Entities/AzuraCastEntity.cs b/AzzyBot-Next/Database/Entities/AzuraCastEntity.cs index fd5f6cc6..29d101f9 100644 --- a/AzzyBot-Next/Database/Entities/AzuraCastEntity.cs +++ b/AzzyBot-Next/Database/Entities/AzuraCastEntity.cs @@ -13,6 +13,7 @@ public sealed class AzuraCastEntity public string AdminApiKey { get; set; } = string.Empty; public ulong NotificationChannelId { get; set; } public ulong OutagesChannelId { get; set; } + public AzuraCastChecksEntity Checks { get; set; } = new(); public ICollection Stations { get; } = new List(); public int? GuildId { get; set; } diff --git a/AzzyBot-Next/Database/Entities/AzuraCastStationChecksEntity.cs b/AzzyBot-Next/Database/Entities/AzuraCastStationChecksEntity.cs new file mode 100644 index 00000000..b966b39d --- /dev/null +++ b/AzzyBot-Next/Database/Entities/AzuraCastStationChecksEntity.cs @@ -0,0 +1,15 @@ +using System.Diagnostics.CodeAnalysis; + +namespace AzzyBot.Database.Entities; + +[SuppressMessage("Roslynator", "RCS0036:Remove blank line between single-line declarations of same kind", Justification = "Better clarification on keys")] +public sealed class AzuraCastStationChecksEntity +{ + public int Id { get; set; } + + public bool FileChanges { get; set; } + public bool ServerStatus { get; set; } + + public int StationId { get; set; } + public AzuraCastStationEntity Station { get; set; } = null!; +} diff --git a/AzzyBot-Next/Database/Entities/AzuraCastStationEntity.cs b/AzzyBot-Next/Database/Entities/AzuraCastStationEntity.cs index 3e065235..f4fa28be 100644 --- a/AzzyBot-Next/Database/Entities/AzuraCastStationEntity.cs +++ b/AzzyBot-Next/Database/Entities/AzuraCastStationEntity.cs @@ -11,8 +11,8 @@ public sealed class AzuraCastStationEntity public int StationId { get; set; } public string Name { get; set; } = string.Empty; public string ApiKey { get; set; } = string.Empty; - public AzuraCastChecksEntity Checks { get; set; } = new(); - public ICollection Mounts { get; } = new List(); + public AzuraCastStationChecksEntity Checks { get; set; } = new(); + public ICollection Mounts { get; } = new List(); public ulong RequestsChannelId { get; set; } public bool PreferHls { get; set; } public bool ShowPlaylistInNowPlaying { get; set; } diff --git a/AzzyBot-Next/Database/Entities/AzuraCastMountEntity.cs b/AzzyBot-Next/Database/Entities/AzuraCastStationMountEntity.cs similarity index 90% rename from AzzyBot-Next/Database/Entities/AzuraCastMountEntity.cs rename to AzzyBot-Next/Database/Entities/AzuraCastStationMountEntity.cs index f74bd6ed..776c4c62 100644 --- a/AzzyBot-Next/Database/Entities/AzuraCastMountEntity.cs +++ b/AzzyBot-Next/Database/Entities/AzuraCastStationMountEntity.cs @@ -3,7 +3,7 @@ namespace AzzyBot.Database.Entities; [SuppressMessage("Roslynator", "RCS0036:Remove blank line between single-line declarations of same kind", Justification = "Better clarification on keys")] -public sealed class AzuraCastMountEntity +public sealed class AzuraCastStationMountEntity { public int Id { get; set; } diff --git a/AzzyBot-Next/Logging/LoggerActions.cs b/AzzyBot-Next/Logging/LoggerActions.cs index 35f50142..91689fd7 100644 --- a/AzzyBot-Next/Logging/LoggerActions.cs +++ b/AzzyBot-Next/Logging/LoggerActions.cs @@ -30,7 +30,7 @@ public static partial class LoggerActions public static partial void BackgroundServiceHostRun(this ILogger logger); [LoggerMessage(13, LogLevel.Debug, "Creating work items...")] - public static partial void AzuraCastFileServiceWorkItem(this ILogger logger); + public static partial void BackgroundServiceWorkItem(this ILogger logger); [LoggerMessage(90, LogLevel.Debug, "Stopping global timer")] public static partial void GlobalTimerStop(this ILogger logger); diff --git a/AzzyBot-Next/Migrations/20240609204920_InitialCreation.Designer.cs b/AzzyBot-Next/Migrations/20240610192325_InitialCreation.Designer.cs similarity index 85% rename from AzzyBot-Next/Migrations/20240609204920_InitialCreation.Designer.cs rename to AzzyBot-Next/Migrations/20240610192325_InitialCreation.Designer.cs index e8639f37..6f8703a4 100644 --- a/AzzyBot-Next/Migrations/20240609204920_InitialCreation.Designer.cs +++ b/AzzyBot-Next/Migrations/20240610192325_InitialCreation.Designer.cs @@ -12,7 +12,7 @@ namespace AzzyBot.Migrations { [DbContext(typeof(AzzyDbContext))] - [Migration("20240609204920_InitialCreation")] + [Migration("20240610192325_InitialCreation")] partial class InitialCreation { /// @@ -33,15 +33,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - b.Property("FileChanges") - .HasColumnType("tinyint(1)"); + b.Property("AzuraCastId") + .HasColumnType("int"); b.Property("ServerStatus") .HasColumnType("tinyint(1)"); - b.Property("StationId") - .HasColumnType("int"); - b.Property("Updates") .HasColumnType("tinyint(1)"); @@ -50,7 +47,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("StationId") + b.HasIndex("AzuraCastId") .IsUnique(); b.ToTable("AzuraCastChecks"); @@ -89,7 +86,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AzuraCast"); }); - modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastMountEntity", b => + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationChecksEntity", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -97,22 +94,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - b.Property("Mount") - .IsRequired() - .HasColumnType("longtext"); + b.Property("FileChanges") + .HasColumnType("tinyint(1)"); - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); + b.Property("ServerStatus") + .HasColumnType("tinyint(1)"); b.Property("StationId") .HasColumnType("int"); b.HasKey("Id"); - b.HasIndex("StationId"); + b.HasIndex("StationId") + .IsUnique(); - b.ToTable("AzuraCastMounts"); + b.ToTable("AzuraCastStationChecks"); }); modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationEntity", b => @@ -153,6 +149,32 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("AzuraCastStations"); }); + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationMountEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Mount") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StationId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StationId"); + + b.ToTable("AzuraCastMounts"); + }); + modelBuilder.Entity("AzzyBot.Database.Entities.GuildsEntity", b => { b.Property("Id") @@ -183,13 +205,13 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastChecksEntity", b => { - b.HasOne("AzzyBot.Database.Entities.AzuraCastStationEntity", "Station") + b.HasOne("AzzyBot.Database.Entities.AzuraCastEntity", "AzuraCast") .WithOne("Checks") - .HasForeignKey("AzzyBot.Database.Entities.AzuraCastChecksEntity", "StationId") + .HasForeignKey("AzzyBot.Database.Entities.AzuraCastChecksEntity", "AzuraCastId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Station"); + b.Navigation("AzuraCast"); }); modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastEntity", b => @@ -201,11 +223,11 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Guild"); }); - modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastMountEntity", b => + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationChecksEntity", b => { b.HasOne("AzzyBot.Database.Entities.AzuraCastStationEntity", "Station") - .WithMany("Mounts") - .HasForeignKey("StationId") + .WithOne("Checks") + .HasForeignKey("AzzyBot.Database.Entities.AzuraCastStationChecksEntity", "StationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -223,8 +245,22 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("AzuraCast"); }); + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationMountEntity", b => + { + b.HasOne("AzzyBot.Database.Entities.AzuraCastStationEntity", "Station") + .WithMany("Mounts") + .HasForeignKey("StationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Station"); + }); + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastEntity", b => { + b.Navigation("Checks") + .IsRequired(); + b.Navigation("Stations"); }); diff --git a/AzzyBot-Next/Migrations/20240609204920_InitialCreation.cs b/AzzyBot-Next/Migrations/20240610192325_InitialCreation.cs similarity index 84% rename from AzzyBot-Next/Migrations/20240609204920_InitialCreation.cs rename to AzzyBot-Next/Migrations/20240610192325_InitialCreation.cs index 8ef66152..6b75d156 100644 --- a/AzzyBot-Next/Migrations/20240609204920_InitialCreation.cs +++ b/AzzyBot-Next/Migrations/20240610192325_InitialCreation.cs @@ -57,6 +57,29 @@ protected override void Up(MigrationBuilder migrationBuilder) }) .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( + name: "AzuraCastChecks", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + ServerStatus = table.Column(type: "tinyint(1)", nullable: false), + Updates = table.Column(type: "tinyint(1)", nullable: false), + UpdatesShowChangelog = table.Column(type: "tinyint(1)", nullable: false), + AzuraCastId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AzuraCastChecks", x => x.Id); + table.ForeignKey( + name: "FK_AzuraCastChecks_AzuraCast_AzuraCastId", + column: x => x.AzuraCastId, + principalTable: "AzuraCast", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( name: "AzuraCastStations", columns: table => new @@ -86,22 +109,22 @@ protected override void Up(MigrationBuilder migrationBuilder) .Annotation("MySql:CharSet", "utf8mb4"); migrationBuilder.CreateTable( - name: "AzuraCastChecks", + name: "AzuraCastMounts", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), - FileChanges = table.Column(type: "tinyint(1)", nullable: false), - ServerStatus = table.Column(type: "tinyint(1)", nullable: false), - Updates = table.Column(type: "tinyint(1)", nullable: false), - UpdatesShowChangelog = table.Column(type: "tinyint(1)", nullable: false), + Name = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Mount = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), StationId = table.Column(type: "int", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_AzuraCastChecks", x => x.Id); + table.PrimaryKey("PK_AzuraCastMounts", x => x.Id); table.ForeignKey( - name: "FK_AzuraCastChecks_AzuraCastStations_StationId", + name: "FK_AzuraCastMounts_AzuraCastStations_StationId", column: x => x.StationId, principalTable: "AzuraCastStations", principalColumn: "Id", @@ -110,22 +133,20 @@ protected override void Up(MigrationBuilder migrationBuilder) .Annotation("MySql:CharSet", "utf8mb4"); migrationBuilder.CreateTable( - name: "AzuraCastMounts", + name: "AzuraCastStationChecks", columns: table => new { Id = table.Column(type: "int", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), - Name = table.Column(type: "longtext", nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"), - Mount = table.Column(type: "longtext", nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"), + FileChanges = table.Column(type: "tinyint(1)", nullable: false), + ServerStatus = table.Column(type: "tinyint(1)", nullable: false), StationId = table.Column(type: "int", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_AzuraCastMounts", x => x.Id); + table.PrimaryKey("PK_AzuraCastStationChecks", x => x.Id); table.ForeignKey( - name: "FK_AzuraCastMounts_AzuraCastStations_StationId", + name: "FK_AzuraCastStationChecks_AzuraCastStations_StationId", column: x => x.StationId, principalTable: "AzuraCastStations", principalColumn: "Id", @@ -140,9 +161,9 @@ protected override void Up(MigrationBuilder migrationBuilder) unique: true); migrationBuilder.CreateIndex( - name: "IX_AzuraCastChecks_StationId", + name: "IX_AzuraCastChecks_AzuraCastId", table: "AzuraCastChecks", - column: "StationId", + column: "AzuraCastId", unique: true); migrationBuilder.CreateIndex( @@ -150,6 +171,12 @@ protected override void Up(MigrationBuilder migrationBuilder) table: "AzuraCastMounts", column: "StationId"); + migrationBuilder.CreateIndex( + name: "IX_AzuraCastStationChecks_StationId", + table: "AzuraCastStationChecks", + column: "StationId", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AzuraCastStations_AzuraCastId", table: "AzuraCastStations", @@ -165,6 +192,9 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationBuilder.DropTable( name: "AzuraCastMounts"); + migrationBuilder.DropTable( + name: "AzuraCastStationChecks"); + migrationBuilder.DropTable( name: "AzuraCastStations"); diff --git a/AzzyBot-Next/Migrations/AzzyDbContextModelSnapshot.cs b/AzzyBot-Next/Migrations/AzzyDbContextModelSnapshot.cs index 6b542483..8141a895 100644 --- a/AzzyBot-Next/Migrations/AzzyDbContextModelSnapshot.cs +++ b/AzzyBot-Next/Migrations/AzzyDbContextModelSnapshot.cs @@ -30,15 +30,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - b.Property("FileChanges") - .HasColumnType("tinyint(1)"); + b.Property("AzuraCastId") + .HasColumnType("int"); b.Property("ServerStatus") .HasColumnType("tinyint(1)"); - b.Property("StationId") - .HasColumnType("int"); - b.Property("Updates") .HasColumnType("tinyint(1)"); @@ -47,7 +44,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("StationId") + b.HasIndex("AzuraCastId") .IsUnique(); b.ToTable("AzuraCastChecks"); @@ -86,7 +83,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AzuraCast"); }); - modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastMountEntity", b => + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationChecksEntity", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -94,22 +91,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - b.Property("Mount") - .IsRequired() - .HasColumnType("longtext"); + b.Property("FileChanges") + .HasColumnType("tinyint(1)"); - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); + b.Property("ServerStatus") + .HasColumnType("tinyint(1)"); b.Property("StationId") .HasColumnType("int"); b.HasKey("Id"); - b.HasIndex("StationId"); + b.HasIndex("StationId") + .IsUnique(); - b.ToTable("AzuraCastMounts"); + b.ToTable("AzuraCastStationChecks"); }); modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationEntity", b => @@ -150,6 +146,32 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AzuraCastStations"); }); + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationMountEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Mount") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StationId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StationId"); + + b.ToTable("AzuraCastMounts"); + }); + modelBuilder.Entity("AzzyBot.Database.Entities.GuildsEntity", b => { b.Property("Id") @@ -180,13 +202,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastChecksEntity", b => { - b.HasOne("AzzyBot.Database.Entities.AzuraCastStationEntity", "Station") + b.HasOne("AzzyBot.Database.Entities.AzuraCastEntity", "AzuraCast") .WithOne("Checks") - .HasForeignKey("AzzyBot.Database.Entities.AzuraCastChecksEntity", "StationId") + .HasForeignKey("AzzyBot.Database.Entities.AzuraCastChecksEntity", "AzuraCastId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Station"); + b.Navigation("AzuraCast"); }); modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastEntity", b => @@ -198,11 +220,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Guild"); }); - modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastMountEntity", b => + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationChecksEntity", b => { b.HasOne("AzzyBot.Database.Entities.AzuraCastStationEntity", "Station") - .WithMany("Mounts") - .HasForeignKey("StationId") + .WithOne("Checks") + .HasForeignKey("AzzyBot.Database.Entities.AzuraCastStationChecksEntity", "StationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -220,8 +242,22 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("AzuraCast"); }); + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastStationMountEntity", b => + { + b.HasOne("AzzyBot.Database.Entities.AzuraCastStationEntity", "Station") + .WithMany("Mounts") + .HasForeignKey("StationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Station"); + }); + modelBuilder.Entity("AzzyBot.Database.Entities.AzuraCastEntity", b => { + b.Navigation("Checks") + .IsRequired(); + b.Navigation("Stations"); }); diff --git a/AzzyBot-Next/Services/Modules/AzuraCastFileService.cs b/AzzyBot-Next/Services/Modules/AzuraCastFileService.cs index 01febdb3..d355c2bd 100644 --- a/AzzyBot-Next/Services/Modules/AzuraCastFileService.cs +++ b/AzzyBot-Next/Services/Modules/AzuraCastFileService.cs @@ -41,7 +41,7 @@ public async ValueTask QueueFileChangesChecksAsync() private async ValueTask CheckForFileChangesAsync(AzuraCastStationEntity station, CancellationToken cancellationToken) { - _logger.AzuraCastFileServiceWorkItem(); + _logger.BackgroundServiceWorkItem(); cancellationToken.ThrowIfCancellationRequested(); @@ -61,8 +61,6 @@ private async ValueTask CheckForFileChangesAsync(AzuraCastStationEntity station, { _logger.OperationCanceled(nameof(CheckForFileChangesAsync)); } - - return; } private async ValueTask CheckIfFilesWereModifiedAsync(IReadOnlyList onlineFiles, IReadOnlyList localFiles, int stationDbId, int stationId, string stationName, ulong channelId) diff --git a/AzzyBot-Next/Services/UpdaterService.cs b/AzzyBot-Next/Services/UpdaterService.cs index e6adee39..f20788bc 100644 --- a/AzzyBot-Next/Services/UpdaterService.cs +++ b/AzzyBot-Next/Services/UpdaterService.cs @@ -1,20 +1,28 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; +using AzzyBot.Database; +using AzzyBot.Database.Entities; using AzzyBot.Logging; +using AzzyBot.Services.Interfaces; using AzzyBot.Settings; using AzzyBot.Utilities; +using AzzyBot.Utilities.Encryption; using AzzyBot.Utilities.Records; using DSharpPlus.Entities; using Microsoft.Extensions.Logging; namespace AzzyBot.Services; -public sealed class UpdaterService(AzzyBotSettingsRecord settings, DiscordBotService botService, WebRequestService webService, ILogger logger) +public sealed class UpdaterService(ILogger logger, IQueuedBackgroundTask taskQueue, AzzyBotSettingsRecord settings, DbActions dbActions, DiscordBotService botService, WebRequestService webService) { private readonly ILogger _logger = logger; + private readonly IQueuedBackgroundTask _taskQueue = taskQueue; private readonly AzzyBotSettingsRecord _settings = settings; + private readonly DbActions _dbActions = dbActions; private readonly DiscordBotService _botService = botService; private readonly WebRequestService _webService = webService; private DateTime _lastAzzyUpdateNotificationTime = DateTime.MinValue; @@ -23,6 +31,33 @@ public sealed class UpdaterService(AzzyBotSettingsRecord settings, DiscordBotSer private readonly Uri _latestUrl = new("https://api.github.com/repos/Sella-GH/AzzyBot/releases/latest"); private readonly Uri _previewUrl = new("https://api.github.com/repos/Sella-GH/AzzyBot/releases"); + public async ValueTask QueueAzuraCastUpdatesAsync() + { + List guilds = await _dbActions.GetGuildsAsync(); + foreach (AzuraCastEntity azuraCast in guilds.Where(g => g.AzuraCast?.Checks.Updates == true).Select(g => g.AzuraCast!)) + { + _ = Task.Run(async () => await _taskQueue.QueueBackgroundWorkItemAsync(async ct => await CheckForAzuraCastUpdatesAsync(azuraCast, ct))); + } + } + + private async ValueTask CheckForAzuraCastUpdatesAsync(AzuraCastEntity azuraCast, CancellationToken cancellationToken) + { + _logger.BackgroundServiceWorkItem(); + + cancellationToken.ThrowIfCancellationRequested(); + + try + { + string apiKey = Crypto.Decrypt(azuraCast.AdminApiKey); + + + } + catch (OperationCanceledException) + { + _logger.OperationCanceled(nameof(CheckForAzuraCastUpdatesAsync)); + } + } + public async Task CheckForAzzyUpdatesAsync() { string localVersion = AzzyStatsSoftware.GetBotVersion; @@ -74,7 +109,7 @@ private async Task SendUpdateMessageAsync(string updateVersion, DateTime release _azzyNotifyCounter = 0; } - if (!ChecKUpdateNotification(_azzyNotifyCounter, _lastAzzyUpdateNotificationTime)) + if (!CheckUpdateNotification(_azzyNotifyCounter, _lastAzzyUpdateNotificationTime)) return; _lastAzzyUpdateNotificationTime = DateTime.Now; @@ -108,7 +143,7 @@ private async Task SendUpdateMessageAsync(string updateVersion, DateTime release await _botService.SendMessageAsync(channelId, null, embeds); } - private static bool ChecKUpdateNotification(int notifyCounter, in DateTime lastNotificationTime) + private static bool CheckUpdateNotification(int notifyCounter, in DateTime lastNotificationTime) { DateTime now = DateTime.Now; bool dayNotification = false; diff --git a/AzzyBot-Next/Utilities/EmbedBuilder.cs b/AzzyBot-Next/Utilities/EmbedBuilder.cs index 58924490..8dfb50a0 100644 --- a/AzzyBot-Next/Utilities/EmbedBuilder.cs +++ b/AzzyBot-Next/Utilities/EmbedBuilder.cs @@ -467,6 +467,8 @@ public static IReadOnlyList BuildGetSettingsAzuraEmbed(AzuraCastEn ["Base Url"] = new($"||{((!string.IsNullOrWhiteSpace(azuraCast.BaseUrl)) ? Crypto.Decrypt(azuraCast.BaseUrl) : "Not set")}||"), ["Admin Api Key"] = new($"||{((!string.IsNullOrWhiteSpace(azuraCast.AdminApiKey)) ? Crypto.Decrypt(azuraCast.AdminApiKey) : "Not set")}||"), ["Notification Channel"] = new((azuraCast.NotificationChannelId > 0) ? $"<#{azuraCast.NotificationChannelId}>" : "Not set"), + ["Updates"] = new(azuraCast.Checks.Updates.ToString()), + ["Updates Show Changelog"] = new(azuraCast.Checks.UpdatesShowChangelog.ToString()), ["Outages Channel"] = new((azuraCast.OutagesChannelId > 0) ? $"<#{azuraCast.OutagesChannelId}>" : "Not set") }; @@ -483,7 +485,7 @@ public static IReadOnlyList BuildGetSettingsAzuraEmbed(AzuraCastEn ["Music Requests Channel"] = new((station.RequestsChannelId > 0) ? $"<#{station.RequestsChannelId}>" : "Not set"), ["Prefer HLS Streaming"] = new(station.PreferHls.ToString()), ["Show Playlist In Now Playing"] = new(station.ShowPlaylistInNowPlaying.ToString()), - ["Automatic Checks"] = new($"- File Changes: {station.Checks.FileChanges}\n- Server Status: {station.Checks.ServerStatus}\n- Updates: {station.Checks.Updates}\n- Updates Changelog: {station.Checks.UpdatesShowChangelog}"), + ["Automatic Checks"] = new($"- File Changes: {station.Checks.FileChanges}\n- Server Status: {station.Checks.ServerStatus}"), ["Mount Points"] = new((station.Mounts.Count > 0) ? string.Join('\n', station.Mounts.Select(x => $"- {Crypto.Decrypt(x.Name)}: {Crypto.Decrypt(x.Mount)}")) : "No Mount Points added") };